rugl 0.1.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.
- checksums.yaml +7 -0
- data/LICENSE.txt +21 -0
- data/README.md +293 -0
- data/Rakefile +12 -0
- data/examples/batch.rb +63 -0
- data/examples/example_helper.rb +6 -0
- data/examples/framebuffer.rb +76 -0
- data/examples/scope.rb +65 -0
- data/examples/triangle.rb +36 -0
- data/lib/rugl/backends/opengl_bindings.rb +324 -0
- data/lib/rugl/command.rb +236 -0
- data/lib/rugl/command_compiler.rb +192 -0
- data/lib/rugl/context.rb +500 -0
- data/lib/rugl/dynamic.rb +88 -0
- data/lib/rugl/resources/base.rb +93 -0
- data/lib/rugl/resources/buffer.rb +153 -0
- data/lib/rugl/resources/elements.rb +127 -0
- data/lib/rugl/resources/framebuffer.rb +183 -0
- data/lib/rugl/resources/renderbuffer.rb +63 -0
- data/lib/rugl/resources/texture.rb +179 -0
- data/lib/rugl/resources/vao.rb +63 -0
- data/lib/rugl/shader.rb +146 -0
- data/lib/rugl/state/blend.rb +117 -0
- data/lib/rugl/state/color_mask.rb +27 -0
- data/lib/rugl/state/cull.rb +27 -0
- data/lib/rugl/state/depth.rb +33 -0
- data/lib/rugl/state/polygon_offset.rb +40 -0
- data/lib/rugl/state/scissor.rb +40 -0
- data/lib/rugl/state/stencil.rb +96 -0
- data/lib/rugl/state_manager.rb +137 -0
- data/lib/rugl/util.rb +347 -0
- data/lib/rugl/version.rb +5 -0
- data/lib/rugl.rb +44 -0
- metadata +132 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 4dd4f813b58ccae38822027f48263c23a4e2e89a19a4f45a04c10542eee35784
|
|
4
|
+
data.tar.gz: 0bc5750099f8ce7d8f087bda51996ae9480efea9972065d0f403d2f07bfc090e
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 6047ff624719eb0a15179a639ff12765d041e36ce30823ca7ad43e01c4dcd91498eceab9c5ddfbf1fa1e317893f5e229e3358570a8f4dd1fc4d2d1352d486b02
|
|
7
|
+
data.tar.gz: efd1efe350e4233e2f6327ba0c9befc2b0c15b9f27b2b80214c5378bd87336ba4b113bdbd54c375d2cc0fa0d92a4d23f0d3fbe29949b94f254aab64668a969a1
|
data/LICENSE.txt
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Yudai Takada
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
|
13
|
+
all copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
# Rugl
|
|
2
|
+
|
|
3
|
+
Functional OpenGL for Ruby.
|
|
4
|
+
|
|
5
|
+
Rugl is a small command-oriented rendering layer on top of OpenGL bindings. You describe draw calls as immutable Ruby hashes, resolve dynamic values at execution time, and let Rugl handle shader compilation, VAO setup, resource tracking, and render-state diffing.
|
|
6
|
+
|
|
7
|
+
## Current Feature Set
|
|
8
|
+
|
|
9
|
+
- `Rugl.create` builds a rendering context and can bootstrap a default GLFW window/context
|
|
10
|
+
- `rugl.command(...)` compiles reusable draw commands from shader source plus draw/state options
|
|
11
|
+
- dynamic values can come from runtime props, frame context, scoped props, or procs
|
|
12
|
+
- commands support single draws, batched draws, indexed draws, instancing, scoped execution, and framebuffer targets
|
|
13
|
+
- GPU resources include buffers, element buffers, textures, renderbuffers, and framebuffers
|
|
14
|
+
- render state diffing covers `depth`, `blend`, `stencil`, `scissor`, `cull`, `polygon_offset`, `color_mask`, `front_face`, `line_width`, `dither`, `sample`, and `viewport`
|
|
15
|
+
- context helpers include `clear`, `read`, `limits`, and `has_extension?`
|
|
16
|
+
|
|
17
|
+
## Installation
|
|
18
|
+
|
|
19
|
+
### Runtime requirements
|
|
20
|
+
|
|
21
|
+
- Ruby 3.1+
|
|
22
|
+
- [`opengl-bindings`](https://rubygems.org/gems/opengl-bindings) for OpenGL symbols
|
|
23
|
+
- `glfw` only if you want `Rugl.create` to open a default window/context for you
|
|
24
|
+
|
|
25
|
+
### System dependencies
|
|
26
|
+
|
|
27
|
+
If you want Rugl to create its own window/context via GLFW, install GLFW and OpenGL development libraries first.
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
# Ubuntu / Debian
|
|
31
|
+
sudo apt-get install libglfw3-dev libgl1-mesa-dev
|
|
32
|
+
|
|
33
|
+
# macOS
|
|
34
|
+
brew install glfw
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### Gem install
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
gem install rugl
|
|
41
|
+
gem install glfw # optional, only for the default window/context path
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Or in your `Gemfile`:
|
|
45
|
+
|
|
46
|
+
```ruby
|
|
47
|
+
gem "rugl", git: "https://github.com/ydah/rugl"
|
|
48
|
+
gem "glfw" # optional
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Quick Start
|
|
52
|
+
|
|
53
|
+
```ruby
|
|
54
|
+
require "rugl"
|
|
55
|
+
|
|
56
|
+
rugl = Rugl.create(width: 800, height: 600, title: "Rugl Triangle")
|
|
57
|
+
|
|
58
|
+
draw_triangle = rugl.command(
|
|
59
|
+
vert: <<~GLSL,
|
|
60
|
+
#version 410 core
|
|
61
|
+
layout(location = 0) in vec2 position;
|
|
62
|
+
void main() {
|
|
63
|
+
gl_Position = vec4(position, 0.0, 1.0);
|
|
64
|
+
}
|
|
65
|
+
GLSL
|
|
66
|
+
frag: <<~GLSL,
|
|
67
|
+
#version 410 core
|
|
68
|
+
uniform vec4 color;
|
|
69
|
+
out vec4 fragColor;
|
|
70
|
+
void main() {
|
|
71
|
+
fragColor = color;
|
|
72
|
+
}
|
|
73
|
+
GLSL
|
|
74
|
+
attributes: {
|
|
75
|
+
position: rugl.buffer([[-2, -2], [4, -2], [4, 4]])
|
|
76
|
+
},
|
|
77
|
+
uniforms: {
|
|
78
|
+
color: Rugl.prop(:color)
|
|
79
|
+
},
|
|
80
|
+
count: 3
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
rugl.frame do |ctx|
|
|
84
|
+
rugl.clear(color: [0.0, 0.0, 0.0, 1.0], depth: 1.0)
|
|
85
|
+
|
|
86
|
+
t = ctx[:time]
|
|
87
|
+
draw_triangle.call(
|
|
88
|
+
color: [Math.cos(t), Math.sin(t * 0.8), Math.cos(t * 0.3), 1.0]
|
|
89
|
+
)
|
|
90
|
+
end
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## Core Concepts
|
|
94
|
+
|
|
95
|
+
### Context
|
|
96
|
+
|
|
97
|
+
`Rugl.create(**opts)` returns a `Rugl::Context`.
|
|
98
|
+
|
|
99
|
+
Important context options:
|
|
100
|
+
|
|
101
|
+
- `width:`, `height:`, `title:` control the default GLFW window
|
|
102
|
+
- `version:` defaults to `[4, 1]`
|
|
103
|
+
- `profile:` defaults to `:core`
|
|
104
|
+
- `samples:` enables multisample hints when GLFW is available
|
|
105
|
+
- `debug:` enables shader/program/GL error checks
|
|
106
|
+
- `gl:`, `glfw:`, and `window:` let you inject your own backends
|
|
107
|
+
- `auto_init: false` disables default backend/window setup
|
|
108
|
+
|
|
109
|
+
Useful context methods:
|
|
110
|
+
|
|
111
|
+
- `rugl.command(opts)` compiles a command
|
|
112
|
+
- `rugl.frame(max_frames: nil) { |ctx| ... }` runs the frame loop
|
|
113
|
+
- `rugl.clear(color: nil, depth: nil, stencil: nil)` clears active buffers
|
|
114
|
+
- `rugl.read(x: 0, y: 0, width: nil, height: nil)` reads RGBA pixels into a binary string
|
|
115
|
+
- `rugl.limits` queries a few common GL limits
|
|
116
|
+
- `rugl.has_extension?("GL_EXT_name")` checks extension support
|
|
117
|
+
- `rugl.destroy` destroys the window/context and warns about leaked resources
|
|
118
|
+
|
|
119
|
+
If no window is present, `frame` runs a single iteration by default. That makes `auto_init: false` useful for tests and offscreen/headless flows.
|
|
120
|
+
|
|
121
|
+
### Commands
|
|
122
|
+
|
|
123
|
+
Commands are compiled once and executed many times:
|
|
124
|
+
|
|
125
|
+
```ruby
|
|
126
|
+
draw = rugl.command(
|
|
127
|
+
vert: "...",
|
|
128
|
+
frag: "...",
|
|
129
|
+
attributes: { position: rugl.buffer([...]) },
|
|
130
|
+
uniforms: { color: Rugl.prop(:color) },
|
|
131
|
+
count: 3,
|
|
132
|
+
primitive: :triangles,
|
|
133
|
+
depth: { enable: true },
|
|
134
|
+
blend: { enable: true }
|
|
135
|
+
)
|
|
136
|
+
|
|
137
|
+
draw.call(color: [1, 0, 0, 1])
|
|
138
|
+
draw.call([{ color: [1, 0, 0, 1] }, { color: [0, 1, 0, 1] }])
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
Supported top-level command keys:
|
|
142
|
+
|
|
143
|
+
- shaders: `:vert`, `:frag`
|
|
144
|
+
- draw inputs: `:attributes`, `:uniforms`, `:elements`
|
|
145
|
+
- draw params: `:count`, `:primitive`, `:offset`, `:instances`
|
|
146
|
+
- targets: `:framebuffer`
|
|
147
|
+
- state: `:depth`, `:blend`, `:stencil`, `:scissor`, `:cull`, `:polygon_offset`, `:color_mask`, `:front_face`, `:line_width`, `:dither`, `:sample`, `:viewport`
|
|
148
|
+
|
|
149
|
+
Programs are cached per context by identical vertex/fragment shader source pairs.
|
|
150
|
+
|
|
151
|
+
### Dynamic Values
|
|
152
|
+
|
|
153
|
+
Rugl resolves dynamic values at draw time:
|
|
154
|
+
|
|
155
|
+
```ruby
|
|
156
|
+
Rugl.prop(:color) # runtime props passed to command.call
|
|
157
|
+
Rugl.context(:time) # per-frame context from rugl.frame
|
|
158
|
+
Rugl.this(:model) # current scoped/merged props
|
|
159
|
+
-> { 1.0 } # arity 0
|
|
160
|
+
->(ctx) { ctx[:tick] } # arity 1
|
|
161
|
+
->(ctx, props) { ... } # arity 2+
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
Dynamic markers can be used in uniforms, attributes, draw params, framebuffer targets, and state blocks.
|
|
165
|
+
|
|
166
|
+
### Scoped Execution
|
|
167
|
+
|
|
168
|
+
Passing a block to `command.call` turns the command into a scope. The command applies its state and props, then child commands inherit those merged props through `Rugl.this(...)` and normal prop lookup.
|
|
169
|
+
|
|
170
|
+
```ruby
|
|
171
|
+
scope.call(color: [1, 0.5, 0.2, 1]) do
|
|
172
|
+
child.call
|
|
173
|
+
end
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
## Resources
|
|
177
|
+
|
|
178
|
+
### Buffers
|
|
179
|
+
|
|
180
|
+
```ruby
|
|
181
|
+
positions = rugl.buffer([[-1, -1], [1, -1], [0, 1]])
|
|
182
|
+
dynamic = rugl.buffer(data: [0, 1, 2, 3], usage: :dynamic, type: :float)
|
|
183
|
+
empty = rugl.buffer(byte_length: 4096, usage: :stream)
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
`buffer` accepts either raw array data, an integer byte size, or a hash with `data:`, `byte_length:`, `usage:`, and `type:`.
|
|
187
|
+
|
|
188
|
+
### Element Buffers
|
|
189
|
+
|
|
190
|
+
```ruby
|
|
191
|
+
indices = rugl.elements(data: [0, 1, 2], type: :uint16, primitive: :triangles)
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
`elements` accepts raw index data or a hash with `data:`, `usage:`, `type:`, and `primitive:`.
|
|
195
|
+
|
|
196
|
+
### Textures
|
|
197
|
+
|
|
198
|
+
```ruby
|
|
199
|
+
texture = rugl.texture(
|
|
200
|
+
width: 256,
|
|
201
|
+
height: 256,
|
|
202
|
+
data: Array.new(256 * 256 * 4, 255),
|
|
203
|
+
min_filter: :linear,
|
|
204
|
+
mag_filter: :linear,
|
|
205
|
+
wrap_s: :clamp_to_edge,
|
|
206
|
+
wrap_t: :clamp_to_edge,
|
|
207
|
+
mipmap: true
|
|
208
|
+
)
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
Current texture support is intentionally small:
|
|
212
|
+
|
|
213
|
+
- `Texture` expects a hash source with `width:` and `height:`
|
|
214
|
+
- pixel data can be raw binary or array-like numeric data
|
|
215
|
+
- `format:` currently supports `:rgba`
|
|
216
|
+
- loading image files by path is not built in
|
|
217
|
+
|
|
218
|
+
### Renderbuffers and Framebuffers
|
|
219
|
+
|
|
220
|
+
```ruby
|
|
221
|
+
depth = rugl.renderbuffer(width: 512, height: 512, format: :depth_component24)
|
|
222
|
+
|
|
223
|
+
fbo = rugl.framebuffer(
|
|
224
|
+
width: 512,
|
|
225
|
+
height: 512,
|
|
226
|
+
color: true,
|
|
227
|
+
depth: depth
|
|
228
|
+
)
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
Framebuffer defaults:
|
|
232
|
+
|
|
233
|
+
- `color: true` creates and owns an RGBA texture attachment
|
|
234
|
+
- `depth: true` creates and owns a depth renderbuffer
|
|
235
|
+
- `stencil:` defaults to `false`
|
|
236
|
+
- `depth_stencil:` can be used instead of separate depth/stencil attachments
|
|
237
|
+
|
|
238
|
+
Framebuffer instances expose `color_attachment`, `depth_attachment`, `stencil_attachment`, `depth_stencil_attachment`, `use`, `bind`, `unbind`, `resize`, and `destroy`.
|
|
239
|
+
|
|
240
|
+
## Headless And Injected Backends
|
|
241
|
+
|
|
242
|
+
You can skip GLFW/window creation and inject your own GL backend:
|
|
243
|
+
|
|
244
|
+
```ruby
|
|
245
|
+
require "rugl"
|
|
246
|
+
|
|
247
|
+
gl = MyOpenGLBackend
|
|
248
|
+
rugl = Rugl.create(gl: gl, auto_init: false, width: 256, height: 256)
|
|
249
|
+
|
|
250
|
+
draw = rugl.command(
|
|
251
|
+
vert: "...",
|
|
252
|
+
frag: "...",
|
|
253
|
+
count: 0
|
|
254
|
+
)
|
|
255
|
+
|
|
256
|
+
rugl.frame(max_frames: 1) do
|
|
257
|
+
draw.call
|
|
258
|
+
end
|
|
259
|
+
|
|
260
|
+
pixels = rugl.read(width: 256, height: 256)
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
This is also how most of the test suite exercises the library: with a fake GL backend rather than a real window.
|
|
264
|
+
|
|
265
|
+
## Examples
|
|
266
|
+
|
|
267
|
+
Examples assume `glfw` is installed and available.
|
|
268
|
+
|
|
269
|
+
```bash
|
|
270
|
+
bundle exec ruby examples/triangle.rb
|
|
271
|
+
bundle exec ruby examples/batch.rb
|
|
272
|
+
bundle exec ruby examples/framebuffer.rb
|
|
273
|
+
bundle exec ruby examples/scope.rb
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
- `examples/triangle.rb`: minimal animated triangle
|
|
277
|
+
- `examples/batch.rb`: batched draws with per-instance props
|
|
278
|
+
- `examples/framebuffer.rb`: offscreen render target and texture feedback
|
|
279
|
+
- `examples/scope.rb`: scoped props/state inheritance
|
|
280
|
+
|
|
281
|
+
## Development
|
|
282
|
+
|
|
283
|
+
```bash
|
|
284
|
+
bundle install
|
|
285
|
+
bundle exec rake # default task: spec_unit (`--tag ~gl`)
|
|
286
|
+
bundle exec rake spec # full suite
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
The specs are mostly built around fake GL backends, so they are fast to run without a real OpenGL window.
|
|
290
|
+
|
|
291
|
+
## License
|
|
292
|
+
|
|
293
|
+
MIT License.
|
data/Rakefile
ADDED
data/examples/batch.rb
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "example_helper"
|
|
4
|
+
|
|
5
|
+
rugl = Rugl.create(width: 960, height: 640, title: "Rugl Batch")
|
|
6
|
+
|
|
7
|
+
draw_triangle = rugl.command(
|
|
8
|
+
vert: <<~GLSL,
|
|
9
|
+
#version 410 core
|
|
10
|
+
layout(location = 0) in vec2 position;
|
|
11
|
+
uniform vec2 offset;
|
|
12
|
+
void main() {
|
|
13
|
+
gl_Position = vec4(position * 0.08 + offset, 0.0, 1.0);
|
|
14
|
+
}
|
|
15
|
+
GLSL
|
|
16
|
+
frag: <<~GLSL,
|
|
17
|
+
#version 410 core
|
|
18
|
+
uniform vec4 color;
|
|
19
|
+
out vec4 fragColor;
|
|
20
|
+
void main() {
|
|
21
|
+
fragColor = color;
|
|
22
|
+
}
|
|
23
|
+
GLSL
|
|
24
|
+
attributes: {
|
|
25
|
+
position: rugl.buffer([[-1, -1], [1, -1], [0, 1]])
|
|
26
|
+
},
|
|
27
|
+
uniforms: {
|
|
28
|
+
color: Rugl.prop(:color),
|
|
29
|
+
offset: Rugl.prop(:offset)
|
|
30
|
+
},
|
|
31
|
+
count: 3,
|
|
32
|
+
blend: {
|
|
33
|
+
enable: true,
|
|
34
|
+
func: { src: :src_alpha, dst: :one_minus_src_alpha }
|
|
35
|
+
}
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
grid_size = 10
|
|
39
|
+
cells = grid_size * grid_size
|
|
40
|
+
|
|
41
|
+
rugl.frame do |ctx|
|
|
42
|
+
rugl.clear(color: [0.06, 0.08, 0.12, 1.0], depth: 1.0)
|
|
43
|
+
t = ctx[:time]
|
|
44
|
+
|
|
45
|
+
props = Array.new(cells) do |i|
|
|
46
|
+
x = i % grid_size
|
|
47
|
+
y = i / grid_size
|
|
48
|
+
nx = (x.to_f / (grid_size - 1)) * 2.0 - 1.0
|
|
49
|
+
ny = (y.to_f / (grid_size - 1)) * 2.0 - 1.0
|
|
50
|
+
|
|
51
|
+
{
|
|
52
|
+
offset: [nx, ny],
|
|
53
|
+
color: [
|
|
54
|
+
0.5 + 0.5 * Math.cos(t + x * 0.4),
|
|
55
|
+
0.5 + 0.5 * Math.sin(t * 0.8 + y * 0.5),
|
|
56
|
+
0.5 + 0.5 * Math.cos(t * 0.6 + i * 0.1),
|
|
57
|
+
0.85
|
|
58
|
+
]
|
|
59
|
+
}
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
draw_triangle.call(props)
|
|
63
|
+
end
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "example_helper"
|
|
4
|
+
|
|
5
|
+
rugl = Rugl.create(width: 800, height: 600, title: "Rugl Framebuffer")
|
|
6
|
+
offscreen = rugl.framebuffer(width: 512, height: 512)
|
|
7
|
+
|
|
8
|
+
draw_scene = rugl.command(
|
|
9
|
+
vert: <<~GLSL,
|
|
10
|
+
#version 410 core
|
|
11
|
+
layout(location = 0) in vec2 position;
|
|
12
|
+
uniform float time;
|
|
13
|
+
void main() {
|
|
14
|
+
float a = time;
|
|
15
|
+
mat2 r = mat2(cos(a), -sin(a), sin(a), cos(a));
|
|
16
|
+
vec2 p = r * position;
|
|
17
|
+
gl_Position = vec4(p, 0.0, 1.0);
|
|
18
|
+
}
|
|
19
|
+
GLSL
|
|
20
|
+
frag: <<~GLSL,
|
|
21
|
+
#version 410 core
|
|
22
|
+
out vec4 fragColor;
|
|
23
|
+
void main() {
|
|
24
|
+
fragColor = vec4(0.2, 0.8, 0.5, 1.0);
|
|
25
|
+
}
|
|
26
|
+
GLSL
|
|
27
|
+
attributes: {
|
|
28
|
+
position: rugl.buffer([[-0.7, -0.6], [0.7, -0.6], [0.0, 0.8]])
|
|
29
|
+
},
|
|
30
|
+
uniforms: {
|
|
31
|
+
time: Rugl.context(:time)
|
|
32
|
+
},
|
|
33
|
+
count: 3,
|
|
34
|
+
framebuffer: offscreen
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
draw_quad = rugl.command(
|
|
38
|
+
vert: <<~GLSL,
|
|
39
|
+
#version 410 core
|
|
40
|
+
layout(location = 0) in vec2 position;
|
|
41
|
+
layout(location = 1) in vec2 uv;
|
|
42
|
+
out vec2 vUv;
|
|
43
|
+
void main() {
|
|
44
|
+
vUv = uv;
|
|
45
|
+
gl_Position = vec4(position, 0.0, 1.0);
|
|
46
|
+
}
|
|
47
|
+
GLSL
|
|
48
|
+
frag: <<~GLSL,
|
|
49
|
+
#version 410 core
|
|
50
|
+
in vec2 vUv;
|
|
51
|
+
uniform sampler2D tex;
|
|
52
|
+
out vec4 fragColor;
|
|
53
|
+
void main() {
|
|
54
|
+
fragColor = texture(tex, vUv);
|
|
55
|
+
}
|
|
56
|
+
GLSL
|
|
57
|
+
attributes: {
|
|
58
|
+
position: rugl.buffer([[-1, -1], [1, -1], [1, 1], [-1, 1]]),
|
|
59
|
+
uv: rugl.buffer([[0, 0], [1, 0], [1, 1], [0, 1]])
|
|
60
|
+
},
|
|
61
|
+
uniforms: {
|
|
62
|
+
tex: offscreen.color_attachment
|
|
63
|
+
},
|
|
64
|
+
primitive: :triangle_fan,
|
|
65
|
+
count: 4
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
rugl.frame do
|
|
69
|
+
offscreen.use do
|
|
70
|
+
rugl.clear(color: [0.0, 0.0, 0.0, 1.0], depth: 1.0)
|
|
71
|
+
draw_scene.call
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
rugl.clear(color: [0.03, 0.03, 0.05, 1.0], depth: 1.0)
|
|
75
|
+
draw_quad.call
|
|
76
|
+
end
|
data/examples/scope.rb
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "example_helper"
|
|
4
|
+
|
|
5
|
+
rugl = Rugl.create(width: 800, height: 600, title: "Rugl Scope")
|
|
6
|
+
|
|
7
|
+
draw_triangle = rugl.command(
|
|
8
|
+
vert: <<~GLSL,
|
|
9
|
+
#version 410 core
|
|
10
|
+
layout(location = 0) in vec2 position;
|
|
11
|
+
uniform vec2 offset;
|
|
12
|
+
void main() {
|
|
13
|
+
gl_Position = vec4(position + offset, 0.0, 1.0);
|
|
14
|
+
}
|
|
15
|
+
GLSL
|
|
16
|
+
frag: <<~GLSL,
|
|
17
|
+
#version 410 core
|
|
18
|
+
uniform vec4 color;
|
|
19
|
+
out vec4 fragColor;
|
|
20
|
+
void main() {
|
|
21
|
+
fragColor = color;
|
|
22
|
+
}
|
|
23
|
+
GLSL
|
|
24
|
+
attributes: {
|
|
25
|
+
position: rugl.buffer([[-0.2, -0.2], [0.2, -0.2], [0.0, 0.2]])
|
|
26
|
+
},
|
|
27
|
+
uniforms: {
|
|
28
|
+
offset: Rugl.prop(:offset),
|
|
29
|
+
color: Rugl.prop(:color)
|
|
30
|
+
},
|
|
31
|
+
count: 3
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
scope = rugl.command(
|
|
35
|
+
vert: <<~GLSL,
|
|
36
|
+
#version 410 core
|
|
37
|
+
void main() {
|
|
38
|
+
gl_Position = vec4(0.0);
|
|
39
|
+
}
|
|
40
|
+
GLSL
|
|
41
|
+
frag: <<~GLSL,
|
|
42
|
+
#version 410 core
|
|
43
|
+
uniform vec4 color;
|
|
44
|
+
out vec4 fragColor;
|
|
45
|
+
void main() {
|
|
46
|
+
fragColor = color;
|
|
47
|
+
}
|
|
48
|
+
GLSL
|
|
49
|
+
uniforms: {
|
|
50
|
+
color: Rugl.prop(:color)
|
|
51
|
+
},
|
|
52
|
+
count: 0,
|
|
53
|
+
viewport: { x: 0, y: 0, width: Rugl.context(:viewport_width), height: Rugl.context(:viewport_height) },
|
|
54
|
+
depth: { enable: false }
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
rugl.frame do |ctx|
|
|
58
|
+
rugl.clear(color: [0.08, 0.08, 0.1, 1.0], depth: 1.0)
|
|
59
|
+
t = ctx[:time]
|
|
60
|
+
|
|
61
|
+
scope.call(color: [0.95, 0.6, 0.2, 1.0]) do
|
|
62
|
+
draw_triangle.call(offset: [Math.cos(t) * 0.35, 0.0], color: [0.9, 0.2, 0.3, 1.0])
|
|
63
|
+
draw_triangle.call(offset: [0.0, Math.sin(t * 1.3) * 0.35], color: [0.2, 0.8, 0.9, 1.0])
|
|
64
|
+
end
|
|
65
|
+
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "example_helper"
|
|
4
|
+
|
|
5
|
+
rugl = Rugl.create(width: 800, height: 600, title: "Rugl Triangle")
|
|
6
|
+
|
|
7
|
+
draw_triangle = rugl.command(
|
|
8
|
+
vert: <<~GLSL,
|
|
9
|
+
#version 410 core
|
|
10
|
+
layout(location = 0) in vec2 position;
|
|
11
|
+
void main() {
|
|
12
|
+
gl_Position = vec4(position, 0.0, 1.0);
|
|
13
|
+
}
|
|
14
|
+
GLSL
|
|
15
|
+
frag: <<~GLSL,
|
|
16
|
+
#version 410 core
|
|
17
|
+
uniform vec4 color;
|
|
18
|
+
out vec4 fragColor;
|
|
19
|
+
void main() {
|
|
20
|
+
fragColor = color;
|
|
21
|
+
}
|
|
22
|
+
GLSL
|
|
23
|
+
attributes: {
|
|
24
|
+
position: rugl.buffer([[-2, -2], [4, -2], [4, 4]])
|
|
25
|
+
},
|
|
26
|
+
uniforms: {
|
|
27
|
+
color: Rugl.prop(:color)
|
|
28
|
+
},
|
|
29
|
+
count: 3
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
rugl.frame do |ctx|
|
|
33
|
+
rugl.clear(color: [0.0, 0.0, 0.0, 1.0], depth: 1.0)
|
|
34
|
+
t = ctx[:time]
|
|
35
|
+
draw_triangle.call(color: [Math.cos(t), Math.sin(t * 0.8), Math.cos(t * 0.3), 1.0])
|
|
36
|
+
end
|