rbgl 1.0.0 → 1.0.2
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/.codespellignore +4 -0
- data/.rubocop.yml +3 -0
- data/.yamllint +16 -0
- data/CHANGELOG.md +11 -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 +55 -9
- data/lib/rbgl/engine/clip_space_clipper.rb +23 -3
- data/lib/rbgl/engine/context.rb +23 -6
- data/lib/rbgl/engine/framebuffer.rb +146 -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 +38 -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
data/examples/color_test.rb
CHANGED
|
@@ -52,7 +52,7 @@ while running && !window.should_close?
|
|
|
52
52
|
|
|
53
53
|
events = window.poll_events_raw
|
|
54
54
|
events.each do |e|
|
|
55
|
-
if e[:type] == :key_press &&
|
|
55
|
+
if e[:type] == :key_press && %i[escape q].include?(e[:key])
|
|
56
56
|
running = false
|
|
57
57
|
end
|
|
58
58
|
end
|
data/examples/cube_spinning.rb
CHANGED
|
@@ -67,7 +67,7 @@ view = Mat4.look_at(
|
|
|
67
67
|
|
|
68
68
|
window.on(:key_press) do |event|
|
|
69
69
|
puts "Key pressed: #{event.key}"
|
|
70
|
-
window.stop if
|
|
70
|
+
window.stop if %i[escape q].include?(event.key)
|
|
71
71
|
end
|
|
72
72
|
|
|
73
73
|
puts "Press 'q' or Escape to quit"
|
data/examples/gradient.rb
CHANGED
data/examples/plasma.rb
CHANGED
|
@@ -60,7 +60,7 @@ while running && !window.should_close?
|
|
|
60
60
|
|
|
61
61
|
events = window.poll_events_raw
|
|
62
62
|
events.each do |e|
|
|
63
|
-
if e[:type] == :key_press &&
|
|
63
|
+
if e[:type] == :key_press && %i[escape q].include?(e[:key])
|
|
64
64
|
running = false
|
|
65
65
|
end
|
|
66
66
|
end
|
data/examples/sphere_raymarch.rb
CHANGED
|
@@ -108,7 +108,7 @@ while running && !window.should_close?
|
|
|
108
108
|
|
|
109
109
|
events = window.poll_events_raw
|
|
110
110
|
events.each do |e|
|
|
111
|
-
if e[:type] == :key_press &&
|
|
111
|
+
if e[:type] == :key_press && %i[escape q].include?(e[:key])
|
|
112
112
|
running = false
|
|
113
113
|
end
|
|
114
114
|
end
|
data/examples/triangle_window.rb
CHANGED
data/exe/rbgl
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
|
|
3
|
+
# frozen_string_literal: true
|
|
4
|
+
|
|
5
|
+
require "optparse"
|
|
6
|
+
|
|
7
|
+
lib_path = File.expand_path("../lib", __dir__)
|
|
8
|
+
$LOAD_PATH.unshift(lib_path) unless $LOAD_PATH.include?(lib_path)
|
|
9
|
+
|
|
10
|
+
require "rbgl"
|
|
11
|
+
require "rbgl/cli/doctor"
|
|
12
|
+
|
|
13
|
+
module RBGLCLI
|
|
14
|
+
def self.run(argv = ARGV, stdout: $stdout, stderr: $stderr)
|
|
15
|
+
options = { json: false }
|
|
16
|
+
|
|
17
|
+
parser = OptionParser.new do |parser|
|
|
18
|
+
parser.banner = "Usage: rbgl <command>\n\nCommands:\n doctor [--json]\n"
|
|
19
|
+
parser.on("--json", "Output JSON") { options[:json] = true }
|
|
20
|
+
parser.on("-h", "--help", "Show this help") do
|
|
21
|
+
stdout.puts parser
|
|
22
|
+
return 0
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
parser.parse!(argv)
|
|
27
|
+
|
|
28
|
+
command = argv.shift
|
|
29
|
+
unless command == "doctor"
|
|
30
|
+
stderr.puts parser
|
|
31
|
+
return 1
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
RBGL::CLI::Doctor.new(json: options[:json], io: stdout).run
|
|
35
|
+
rescue OptionParser::InvalidOption, OptionParser::MissingArgument => error
|
|
36
|
+
stderr.puts error.message
|
|
37
|
+
stderr.puts parser
|
|
38
|
+
1
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
exit RBGLCLI.run
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "fileutils"
|
|
4
|
+
require "json"
|
|
5
|
+
require "tmpdir"
|
|
6
|
+
|
|
7
|
+
module RBGL
|
|
8
|
+
module CLI
|
|
9
|
+
class Doctor
|
|
10
|
+
class << self
|
|
11
|
+
def default_checks
|
|
12
|
+
{
|
|
13
|
+
file_backend: ->(doctor, env, platform) { doctor.__send__(:check_file_backend, env, platform) },
|
|
14
|
+
wayland: ->(doctor, env, platform) { doctor.__send__(:check_wayland, env, platform) },
|
|
15
|
+
x11: ->(doctor, env, platform) { doctor.__send__(:check_x11, env, platform) },
|
|
16
|
+
cocoa: ->(doctor, env, platform) { doctor.__send__(:check_cocoa, env, platform) },
|
|
17
|
+
rlsl: ->(doctor, env, platform) { doctor.__send__(:check_rlsl, env, platform) }
|
|
18
|
+
}
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def initialize(json: false, io: $stdout, env: ENV, platform: RUBY_PLATFORM, ruby_version: RUBY_VERSION, checks: {})
|
|
23
|
+
@json = json
|
|
24
|
+
@io = io
|
|
25
|
+
@env = env
|
|
26
|
+
@platform = platform
|
|
27
|
+
@ruby_version = ruby_version
|
|
28
|
+
@checks = self.class.default_checks.merge(checks)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def run
|
|
32
|
+
report = collect
|
|
33
|
+
|
|
34
|
+
if @json
|
|
35
|
+
output_json(report)
|
|
36
|
+
else
|
|
37
|
+
output_text(report)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
0
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def collect
|
|
44
|
+
{
|
|
45
|
+
rbgl_version: RBGL::VERSION,
|
|
46
|
+
ruby_version: @ruby_version,
|
|
47
|
+
platform: @platform,
|
|
48
|
+
file_backend: collect_component(:file_backend),
|
|
49
|
+
wayland: collect_component(:wayland),
|
|
50
|
+
x11: collect_component(:x11),
|
|
51
|
+
cocoa: collect_component(:cocoa),
|
|
52
|
+
rlsl: collect_component(:rlsl)
|
|
53
|
+
}
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
private
|
|
57
|
+
|
|
58
|
+
def collect_component(key)
|
|
59
|
+
@checks.fetch(key).call(self, @env, @platform)
|
|
60
|
+
rescue StandardError => e
|
|
61
|
+
{ available: false, error: "#{e.class}: #{e.message}" }
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def output_text(report)
|
|
65
|
+
@io.puts("RBGL version: #{report[:rbgl_version]}")
|
|
66
|
+
@io.puts("Ruby version: #{report[:ruby_version]}")
|
|
67
|
+
@io.puts("RUBY_PLATFORM: #{report[:platform]}")
|
|
68
|
+
@io.puts
|
|
69
|
+
dump_section("File backend", report[:file_backend])
|
|
70
|
+
dump_section("Wayland", report[:wayland])
|
|
71
|
+
dump_section("X11", report[:x11])
|
|
72
|
+
dump_section("Cocoa", report[:cocoa])
|
|
73
|
+
dump_section("RLSL", report[:rlsl])
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def output_json(report)
|
|
77
|
+
@io.puts(JSON.pretty_generate(report))
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def dump_section(name, values)
|
|
81
|
+
@io.puts("#{name}:")
|
|
82
|
+
values.each do |key, value|
|
|
83
|
+
@io.puts(" #{key}: #{format_value(value)}")
|
|
84
|
+
end
|
|
85
|
+
@io.puts
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def format_value(value)
|
|
89
|
+
return value.is_a?(TrueClass) || value.is_a?(FalseClass) ? (value ? "yes" : "no") : value.inspect
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def check_file_backend(_env, _platform)
|
|
93
|
+
output_dir = Dir.mktmpdir("rbgl-doctor")
|
|
94
|
+
backend = RBGL::GUI::FileBackend.new(1, 1, "rbgl-doctor", output_dir: output_dir)
|
|
95
|
+
backend.present(RBGL::Engine::Framebuffer.new(1, 1))
|
|
96
|
+
|
|
97
|
+
{ available: true, output_dir: output_dir }
|
|
98
|
+
ensure
|
|
99
|
+
backend&.close
|
|
100
|
+
FileUtils.rm_rf(output_dir) if output_dir
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def check_wayland(env, _platform)
|
|
104
|
+
require_ok, require_error = safe_require("rbgl/gui/wayland/connection")
|
|
105
|
+
{
|
|
106
|
+
display_env: env["WAYLAND_DISPLAY"],
|
|
107
|
+
display_available: !env["WAYLAND_DISPLAY"].nil?,
|
|
108
|
+
require_ok: require_ok,
|
|
109
|
+
require_error: require_error
|
|
110
|
+
}
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def check_x11(env, _platform)
|
|
114
|
+
require_ok, require_error = safe_require("rbgl/gui/x11/connection")
|
|
115
|
+
{
|
|
116
|
+
display_env: env["DISPLAY"],
|
|
117
|
+
display_available: !env["DISPLAY"].nil?,
|
|
118
|
+
require_ok: require_ok,
|
|
119
|
+
require_error: require_error
|
|
120
|
+
}
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def check_cocoa(_env, platform)
|
|
124
|
+
darwin = platform.include?("darwin")
|
|
125
|
+
return { platform: platform, supported: false } unless darwin
|
|
126
|
+
|
|
127
|
+
require_ok, require_error = safe_require("metaco")
|
|
128
|
+
{
|
|
129
|
+
platform: platform,
|
|
130
|
+
supported: true,
|
|
131
|
+
require_ok: require_ok,
|
|
132
|
+
require_error: require_error
|
|
133
|
+
}
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def check_rlsl(_env, _platform)
|
|
137
|
+
begin
|
|
138
|
+
require "rlsl"
|
|
139
|
+
version = Gem.loaded_specs["rlsl"]&.version&.to_s
|
|
140
|
+
|
|
141
|
+
{ require_ok: true, version: version }
|
|
142
|
+
rescue LoadError => e
|
|
143
|
+
{ require_ok: false, error: "#{e.class}: #{e.message}" }
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
def safe_require(file)
|
|
148
|
+
require file
|
|
149
|
+
[true, nil]
|
|
150
|
+
rescue LoadError => e
|
|
151
|
+
[false, "#{e.class}: #{e.message}"]
|
|
152
|
+
end
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
end
|
data/lib/rbgl/engine/buffer.rb
CHANGED
|
@@ -6,6 +6,10 @@ module RBGL
|
|
|
6
6
|
attr_reader :name, :size, :offset, :kind
|
|
7
7
|
|
|
8
8
|
def initialize(name, size, offset = 0, kind: nil)
|
|
9
|
+
unless size.is_a?(Integer) && size.positive?
|
|
10
|
+
raise ArgumentError, "Vertex attribute size must be a positive Integer"
|
|
11
|
+
end
|
|
12
|
+
|
|
9
13
|
@name = name.to_sym
|
|
10
14
|
@size = size
|
|
11
15
|
@offset = offset
|
|
@@ -16,7 +20,12 @@ module RBGL
|
|
|
16
20
|
def serialize(value)
|
|
17
21
|
values = extract_values(value)
|
|
18
22
|
validate_value_size!(values)
|
|
19
|
-
values.first(@size).map
|
|
23
|
+
values.first(@size).map do |component|
|
|
24
|
+
number = Float(component)
|
|
25
|
+
raise ArgumentError, "non-finite component" unless number.finite?
|
|
26
|
+
|
|
27
|
+
number
|
|
28
|
+
end
|
|
20
29
|
rescue ArgumentError, TypeError => e
|
|
21
30
|
raise ArgumentError, "Invalid value for attribute #{name}: #{e.message}"
|
|
22
31
|
end
|
|
@@ -96,18 +105,35 @@ module RBGL
|
|
|
96
105
|
end
|
|
97
106
|
|
|
98
107
|
class VertexLayout
|
|
99
|
-
attr_reader :
|
|
108
|
+
attr_reader :stride
|
|
100
109
|
|
|
101
110
|
def initialize(&block)
|
|
102
111
|
@attributes = {}
|
|
103
112
|
@offset = 0
|
|
113
|
+
@stride = 0
|
|
114
|
+
@finalized = false
|
|
104
115
|
instance_eval(&block) if block_given?
|
|
105
|
-
@stride = @offset
|
|
106
116
|
end
|
|
107
117
|
|
|
108
118
|
def attribute(name, size, kind: nil)
|
|
109
|
-
|
|
119
|
+
raise ArgumentError, "Vertex layout is finalized" if @finalized
|
|
120
|
+
|
|
121
|
+
key = name.to_sym
|
|
122
|
+
raise ArgumentError, "Duplicate vertex attribute: #{key}" if @attributes.key?(key)
|
|
123
|
+
|
|
124
|
+
@attributes[key] = VertexAttribute.new(key, size, @offset, kind: kind)
|
|
110
125
|
@offset += size
|
|
126
|
+
@stride = @offset
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
def attributes
|
|
130
|
+
@finalized ? @attributes : @attributes.dup.freeze
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
def finalize!
|
|
134
|
+
@finalized = true
|
|
135
|
+
@attributes.freeze
|
|
136
|
+
self
|
|
111
137
|
end
|
|
112
138
|
|
|
113
139
|
def self.position_only
|
|
@@ -143,7 +169,11 @@ module RBGL
|
|
|
143
169
|
attr_reader :data, :layout, :vertex_count
|
|
144
170
|
|
|
145
171
|
def initialize(layout)
|
|
146
|
-
|
|
172
|
+
unless layout.is_a?(VertexLayout)
|
|
173
|
+
raise ArgumentError, "VertexBuffer layout must be an RBGL::Engine::VertexLayout"
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
@layout = layout.finalize!
|
|
147
177
|
@data = []
|
|
148
178
|
@vertex_count = 0
|
|
149
179
|
end
|
|
@@ -199,14 +229,16 @@ module RBGL
|
|
|
199
229
|
end
|
|
200
230
|
|
|
201
231
|
class IndexBuffer
|
|
202
|
-
attr_reader :indices
|
|
203
|
-
|
|
204
232
|
def initialize(indices = [])
|
|
205
|
-
@indices = indices
|
|
233
|
+
@indices = validate_indices!(indices)
|
|
234
|
+
end
|
|
235
|
+
|
|
236
|
+
def indices
|
|
237
|
+
@indices.dup.freeze
|
|
206
238
|
end
|
|
207
239
|
|
|
208
240
|
def add(*idx)
|
|
209
|
-
@indices.concat(idx.flatten
|
|
241
|
+
@indices.concat(validate_indices!(idx.flatten))
|
|
210
242
|
self
|
|
211
243
|
end
|
|
212
244
|
|
|
@@ -215,6 +247,8 @@ module RBGL
|
|
|
215
247
|
end
|
|
216
248
|
|
|
217
249
|
def get_triangle(index)
|
|
250
|
+
return nil unless index.is_a?(Integer) && index >= 0
|
|
251
|
+
|
|
218
252
|
start = index * 3
|
|
219
253
|
@indices[start, 3]
|
|
220
254
|
end
|
|
@@ -224,6 +258,18 @@ module RBGL
|
|
|
224
258
|
|
|
225
259
|
(0...triangle_count).each { |i| yield get_triangle(i) }
|
|
226
260
|
end
|
|
261
|
+
|
|
262
|
+
private
|
|
263
|
+
|
|
264
|
+
def validate_indices!(indices)
|
|
265
|
+
indices.map do |index|
|
|
266
|
+
unless index.is_a?(Integer) && index >= 0
|
|
267
|
+
raise ArgumentError, "Index must be a non-negative Integer: #{index.inspect}"
|
|
268
|
+
end
|
|
269
|
+
|
|
270
|
+
index
|
|
271
|
+
end
|
|
272
|
+
end
|
|
227
273
|
end
|
|
228
274
|
end
|
|
229
275
|
end
|
|
@@ -13,7 +13,10 @@ module RBGL
|
|
|
13
13
|
].freeze
|
|
14
14
|
|
|
15
15
|
def clip(v0, v1, v2)
|
|
16
|
-
polygon = [v0, v1, v2]
|
|
16
|
+
polygon = [v0, v1, v2].map { |vertex| normalize_vertex(vertex) }
|
|
17
|
+
outcodes = polygon.map { |vertex| outcode(vertex) }
|
|
18
|
+
return [polygon] if outcodes.reduce(:|).zero?
|
|
19
|
+
return [] unless outcodes.reduce(:&).zero?
|
|
17
20
|
|
|
18
21
|
CLIP_PLANES.each do |plane|
|
|
19
22
|
polygon = clip_against_plane(polygon, plane)
|
|
@@ -38,6 +41,11 @@ module RBGL
|
|
|
38
41
|
CLIP_PLANES.all? { |plane| signed_distance(vertex, plane) >= 0 }
|
|
39
42
|
end
|
|
40
43
|
|
|
44
|
+
def clip_point(vertex)
|
|
45
|
+
point = normalize_vertex(vertex)
|
|
46
|
+
visible_point?(point) ? point : nil
|
|
47
|
+
end
|
|
48
|
+
|
|
41
49
|
private
|
|
42
50
|
|
|
43
51
|
def clip_against_plane(vertices, plane)
|
|
@@ -102,7 +110,13 @@ module RBGL
|
|
|
102
110
|
end
|
|
103
111
|
|
|
104
112
|
def duplicate_vertex(vertex)
|
|
105
|
-
ShaderIO.new(vertex.to_h)
|
|
113
|
+
ShaderIO.new(vertex.to_h).tap do |copy|
|
|
114
|
+
copy[:position] = clip_position(vertex) if vertex[:position].is_a?(Larb::Vec2)
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
def normalize_vertex(vertex)
|
|
119
|
+
vertex[:position].is_a?(Larb::Vec2) ? duplicate_vertex(vertex) : vertex
|
|
106
120
|
end
|
|
107
121
|
|
|
108
122
|
def interpolated_keys(start_vertex, finish_vertex)
|
|
@@ -115,7 +129,7 @@ module RBGL
|
|
|
115
129
|
|
|
116
130
|
case start_value
|
|
117
131
|
when Numeric
|
|
118
|
-
start_value + (finish_value - start_value) * t
|
|
132
|
+
start_value + ((finish_value - start_value) * t)
|
|
119
133
|
when Larb::Vec2, Larb::Vec3, Larb::Vec4, Larb::Color
|
|
120
134
|
start_value.lerp(finish_value, t)
|
|
121
135
|
else
|
|
@@ -127,6 +141,12 @@ module RBGL
|
|
|
127
141
|
plane.call(clip_position(vertex))
|
|
128
142
|
end
|
|
129
143
|
|
|
144
|
+
def outcode(vertex)
|
|
145
|
+
CLIP_PLANES.each_with_index.reduce(0) do |code, (plane, index)|
|
|
146
|
+
signed_distance(vertex, plane).negative? ? code | (1 << index) : code
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
|
|
130
150
|
def clip_position(vertex)
|
|
131
151
|
position = vertex[:position]
|
|
132
152
|
|
data/lib/rbgl/engine/context.rb
CHANGED
|
@@ -46,12 +46,18 @@ module RBGL
|
|
|
46
46
|
|
|
47
47
|
def draw_arrays(mode, first, count)
|
|
48
48
|
validate_draw_state!
|
|
49
|
-
|
|
49
|
+
validate_draw_range!(first, count, @vertex_buffer.vertex_count)
|
|
50
|
+
draw_vertices(mode, first...(first + count))
|
|
50
51
|
end
|
|
51
52
|
|
|
52
53
|
def draw_elements(mode, count, offset = 0)
|
|
53
54
|
validate_draw_state!(indexed: true)
|
|
54
|
-
|
|
55
|
+
all_indices = @index_buffer.indices
|
|
56
|
+
validate_draw_range!(offset, count, all_indices.size)
|
|
57
|
+
indices = all_indices[offset, count]
|
|
58
|
+
invalid_index = indices.find { |index| index >= @vertex_buffer.vertex_count }
|
|
59
|
+
raise ArgumentError, "Vertex index out of bounds: #{invalid_index}" if invalid_index
|
|
60
|
+
|
|
55
61
|
draw_vertices(mode, indices, vertex_cache: {})
|
|
56
62
|
end
|
|
57
63
|
|
|
@@ -75,6 +81,15 @@ module RBGL
|
|
|
75
81
|
raise "No index buffer bound" if indexed && !@index_buffer
|
|
76
82
|
end
|
|
77
83
|
|
|
84
|
+
def validate_draw_range!(offset, count, limit)
|
|
85
|
+
unless offset.is_a?(Integer) && count.is_a?(Integer) && offset >= 0 && count >= 0
|
|
86
|
+
raise ArgumentError, "Draw offset and count must be non-negative Integers"
|
|
87
|
+
end
|
|
88
|
+
return if offset + count <= limit
|
|
89
|
+
|
|
90
|
+
raise ArgumentError, "Draw range exceeds available data"
|
|
91
|
+
end
|
|
92
|
+
|
|
78
93
|
def draw_vertices(mode, indices, vertex_cache: nil)
|
|
79
94
|
each_primitive(mode, indices) do |primitive_indices|
|
|
80
95
|
primitive = primitive_indices.map { |index| fetch_vertex(index, vertex_cache) }
|
|
@@ -95,7 +110,7 @@ module RBGL
|
|
|
95
110
|
when :points
|
|
96
111
|
vertices.each { |vertex| yield [vertex] }
|
|
97
112
|
when :triangle_strip
|
|
98
|
-
(0...vertices.size - 2).each do |index|
|
|
113
|
+
(0...(vertices.size - 2)).each do |index|
|
|
99
114
|
if index.even?
|
|
100
115
|
yield [vertices[index], vertices[index + 1], vertices[index + 2]]
|
|
101
116
|
else
|
|
@@ -103,7 +118,7 @@ module RBGL
|
|
|
103
118
|
end
|
|
104
119
|
end
|
|
105
120
|
when :triangle_fan
|
|
106
|
-
(1...vertices.size - 1).each do |index|
|
|
121
|
+
(1...(vertices.size - 1)).each do |index|
|
|
107
122
|
yield [vertices[0], vertices[index], vertices[index + 1]]
|
|
108
123
|
end
|
|
109
124
|
else
|
|
@@ -169,10 +184,12 @@ module RBGL
|
|
|
169
184
|
end
|
|
170
185
|
|
|
171
186
|
def draw_point(v)
|
|
172
|
-
return unless v
|
|
187
|
+
return unless v
|
|
188
|
+
clipped = @clipper.clip_point(v)
|
|
189
|
+
return unless clipped
|
|
173
190
|
|
|
174
191
|
@rasterizer.rasterize_point(
|
|
175
|
-
|
|
192
|
+
clipped,
|
|
176
193
|
@pipeline.fragment_shader,
|
|
177
194
|
@uniforms,
|
|
178
195
|
depth_test: @pipeline.depth_test,
|