processing 1.1.17 → 1.2.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 +4 -4
- data/.github/workflows/release-gem.yml +5 -16
- data/.github/workflows/test-draw.yml +1 -1
- data/.github/workflows/utils.rb +88 -17
- data/ChangeLog.md +17 -0
- data/README.md +186 -5
- data/VERSION +1 -1
- data/lib/processing/all.rb +1 -1
- data/lib/processing/capture.rb +8 -4
- data/lib/processing/context.rb +1 -1
- data/lib/processing/extension.rb +4 -2
- data/lib/processing/graphics_context.rb +29 -9
- data/lib/processing/image.rb +15 -5
- data/lib/processing/shader.rb +9 -7
- data/lib/processing/window.rb +6 -0
- data/processing.gemspec +5 -5
- metadata +10 -10
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 854a85bdbae535597d51821ec8a2b8cc0c948ad355a889bfdd714dbcf2f2ee38
|
|
4
|
+
data.tar.gz: 5ed6cb2ae766ad26658a85826a660be0fbe92575c1b221a8440a38c722d8ec63
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 49a769fbfd6e72f538b007b6da83dae50b873b2f15f1e4240bb4639f90ec459a56b0b1266a8e262aee994ed06e2f01be8e212c1215cbe815f54f188caefdef01
|
|
7
|
+
data.tar.gz: d5cd70ca39f8bd953d322efa398a4325863937c9d28338bd29d7f0004b8882c59d0004e49ca9b8468c89920e0980272f5fd8ad764ff754ebeb137f0b81c02169
|
|
@@ -4,6 +4,9 @@ on:
|
|
|
4
4
|
push:
|
|
5
5
|
tags: ['v[0-9]*']
|
|
6
6
|
|
|
7
|
+
permissions:
|
|
8
|
+
contents: write
|
|
9
|
+
|
|
7
10
|
jobs:
|
|
8
11
|
release:
|
|
9
12
|
runs-on: macos-latest
|
|
@@ -33,23 +36,9 @@ jobs:
|
|
|
33
36
|
echo path=$(ruby -e 'print Dir.glob("*.gem").first') >> $GITHUB_OUTPUT
|
|
34
37
|
|
|
35
38
|
- name: create github release
|
|
36
|
-
id: release
|
|
37
|
-
uses: actions/create-release@v1
|
|
38
39
|
env:
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
tag_name: ${{ github.ref }}
|
|
42
|
-
release_name: ${{ github.ref }}
|
|
43
|
-
|
|
44
|
-
- name: upload to github release
|
|
45
|
-
uses: actions/upload-release-asset@v1
|
|
46
|
-
env:
|
|
47
|
-
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
48
|
-
with:
|
|
49
|
-
upload_url: ${{ steps.release.outputs.upload_url }}
|
|
50
|
-
asset_path: ./${{ steps.gem.outputs.path }}
|
|
51
|
-
asset_name: ${{ steps.gem.outputs.path }}
|
|
52
|
-
asset_content_type: application/zip
|
|
40
|
+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
41
|
+
run: ruby -I.github/workflows -rutils -e 'release(*ARGV)' ./${{ steps.gem.outputs.path }}
|
|
53
42
|
|
|
54
43
|
- name: upload to rubygems
|
|
55
44
|
env:
|
data/.github/workflows/utils.rb
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
require 'shellwords'
|
|
2
|
+
|
|
3
|
+
ALL_REPO = 'xord/all'
|
|
4
|
+
ALL_DIR = '../all'
|
|
5
|
+
ALL_FETCH_DEPTH = 100
|
|
6
|
+
|
|
1
7
|
RENAMES = {reflex: 'reflexion'}
|
|
2
8
|
|
|
3
9
|
def sh(cmd)
|
|
@@ -5,7 +11,7 @@ def sh(cmd)
|
|
|
5
11
|
system cmd
|
|
6
12
|
end
|
|
7
13
|
|
|
8
|
-
def setup_dependencies(
|
|
14
|
+
def setup_dependencies(only: nil)
|
|
9
15
|
gemspec_path = `git ls-files`.lines(chomp: true).find {|l| l =~ /\.gemspec$/}
|
|
10
16
|
return unless gemspec_path
|
|
11
17
|
|
|
@@ -13,44 +19,109 @@ def setup_dependencies(build: true, only: nil)
|
|
|
13
19
|
name = File.basename gemspec_path, '.gemspec'
|
|
14
20
|
|
|
15
21
|
exts = File.readlines('Rakefile')
|
|
16
|
-
.map {|l| l[%r|^\s*require\W+(\w+)/extension\W+$|, 1]}
|
|
22
|
+
.map {|l| l[%r|^\s*require\W+([\w\-\_]+)/extension\W+$|, 1]}
|
|
17
23
|
.compact
|
|
18
24
|
.reject {|ext| ext == name}
|
|
19
25
|
exts = exts & [only].flatten.map(&:to_s) if only
|
|
26
|
+
return if exts.empty?
|
|
27
|
+
|
|
28
|
+
unless setup_dependencies_via_monorepo(exts)
|
|
29
|
+
setup_dependencies_via_each_repo_by_version(gemspec, exts)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
exts.each {|ext| sh %( cd ../#{ext} && rake ext )}
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def setup_dependencies_via_monorepo(exts)
|
|
36
|
+
return false unless checkout_monorepo
|
|
37
|
+
exts.each {|ext| sh %( ln -snf all/#{ext} ../#{ext} )}
|
|
38
|
+
true
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def checkout_monorepo()
|
|
42
|
+
uuid = `git log -1 --format=%B`[/^\[\[([0-9a-fA-F-]+)\]\]$/, 1]
|
|
43
|
+
return false unless uuid
|
|
44
|
+
|
|
45
|
+
commit = setup_monorepo uuid
|
|
46
|
+
return false unless commit
|
|
47
|
+
|
|
48
|
+
Dir.chdir(ALL_DIR) {sh %( git checkout -q #{commit} )}
|
|
49
|
+
true
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def setup_monorepo(uuid)
|
|
53
|
+
unless File.directory? ALL_DIR
|
|
54
|
+
url = "https://github.com/#{ALL_REPO}.git"
|
|
55
|
+
sh %( git clone --no-tags --depth #{ALL_FETCH_DEPTH} #{url} #{ALL_DIR} )
|
|
56
|
+
end
|
|
57
|
+
loop do
|
|
58
|
+
commit = find_monorepo_commit uuid
|
|
59
|
+
return commit if commit
|
|
60
|
+
|
|
61
|
+
deepened = Dir.chdir ALL_DIR do
|
|
62
|
+
before = `git rev-list --count HEAD`.to_i
|
|
63
|
+
sh %( git fetch --deepen #{ALL_FETCH_DEPTH} )
|
|
64
|
+
`git rev-list --count HEAD`.to_i > before
|
|
65
|
+
end
|
|
66
|
+
return nil unless deepened
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def find_monorepo_commit(uuid)
|
|
71
|
+
Dir.chdir ALL_DIR do
|
|
72
|
+
out = `git log origin/HEAD -F --grep="[[#{uuid}]]" --format=%H -1`.strip
|
|
73
|
+
out.empty? ? nil : out
|
|
74
|
+
end
|
|
75
|
+
end
|
|
20
76
|
|
|
77
|
+
def setup_dependencies_via_each_repo_by_version(gemspec, exts)
|
|
21
78
|
exts.each do |ext|
|
|
22
79
|
gem = RENAMES[ext.to_sym].then {|s| s || ext}
|
|
23
|
-
ver = gemspec[/add_dependency.*['"]#{gem}['"].*['"]\s
|
|
80
|
+
ver = gemspec[/add_dependency.*['"]#{gem}['"].*['"]\s*~>\s*([\d\.]+)\s*['"]/, 1]
|
|
24
81
|
opts = '-c advice.detachedHead=false --depth 1'
|
|
25
82
|
clone = "git clone #{opts} https://github.com/xord/#{ext}.git ../#{ext}"
|
|
26
83
|
|
|
27
84
|
# 'rake subtree:push' pushes all subrepos, so cloning by new tag
|
|
28
85
|
# often fails before tagging each new tag
|
|
29
86
|
sh %( #{clone} --branch v#{ver} || #{clone} )
|
|
30
|
-
sh %( cd ../#{ext} && rake ext )
|
|
31
87
|
end
|
|
32
88
|
end
|
|
33
89
|
|
|
34
90
|
def tag_versions()
|
|
35
|
-
|
|
36
|
-
|
|
91
|
+
changes = changelogs
|
|
92
|
+
tags = `git tag`.lines chomp: true
|
|
93
|
+
vers = `git log --oneline ./VERSION`
|
|
37
94
|
.lines(chomp: true)
|
|
38
95
|
.map {|line| line.split.first[/^\w+$/]}
|
|
39
|
-
.map {|
|
|
40
|
-
.select {|ver,
|
|
96
|
+
.map {|sha| [`git cat-file -p #{sha}:./VERSION 2>/dev/null`[/[\d\.]+/], sha]}
|
|
97
|
+
.select {|ver, sha| ver && sha}
|
|
41
98
|
.reverse
|
|
42
99
|
.to_h
|
|
43
100
|
|
|
44
|
-
|
|
45
|
-
.split(/^\s*##\s*\[\s*v([\d\.]+)\s*\].*$/)
|
|
46
|
-
.slice(1..-1)
|
|
47
|
-
.each_slice(2)
|
|
48
|
-
.to_h
|
|
49
|
-
.transform_values(&:strip!)
|
|
50
|
-
|
|
51
|
-
vers.to_a.reverse.each do |ver, hash|
|
|
101
|
+
vers.to_a.reverse.each do |ver, sha|
|
|
52
102
|
tag = "v#{ver}"
|
|
53
103
|
break if tags.include?(tag)
|
|
54
|
-
sh %( git tag -a -m \"#{changes[
|
|
104
|
+
sh %( git tag -a -m \"#{changes[tag]&.gsub '"', '\\"'}\" #{tag} #{sha} )
|
|
55
105
|
end
|
|
56
106
|
end
|
|
107
|
+
|
|
108
|
+
def release(*paths)
|
|
109
|
+
tag = ENV['GITHUB_REF']&.sub(%r|^refs/tags/|, '') || raise('GITHUB_REF tag not set')
|
|
110
|
+
notes = (changelogs[tag] || '').shellescape
|
|
111
|
+
paths = paths.flatten.join ' '
|
|
112
|
+
|
|
113
|
+
sh(%( gh release create #{tag} #{paths} --notes #{notes} )) ||
|
|
114
|
+
sh(%( gh release upload #{tag} #{paths} --clobber )) ||
|
|
115
|
+
raise('failed to upload to releases')
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
def changelogs()
|
|
119
|
+
File.read('ChangeLog.md')
|
|
120
|
+
.split(/^\s*##\s*\[\s*(v[\d\.]+)\s*\].*$/)
|
|
121
|
+
.slice(1..)
|
|
122
|
+
.each_slice(2)
|
|
123
|
+
.to_h
|
|
124
|
+
.transform_values(&:strip!)
|
|
125
|
+
rescue Errno::ENOENT
|
|
126
|
+
raise 'failed to get changelogs'
|
|
127
|
+
end
|
data/ChangeLog.md
CHANGED
|
@@ -1,6 +1,23 @@
|
|
|
1
1
|
# processing ChangeLog
|
|
2
2
|
|
|
3
3
|
|
|
4
|
+
## [v1.2.0] - 2026-05-17
|
|
5
|
+
|
|
6
|
+
- [BREAKING] Wheel Y delta now follows top-left origin convention (from reflex)
|
|
7
|
+
|
|
8
|
+
- Avoid painter.push overhead in image/blend draws
|
|
9
|
+
- Rewrite README.md
|
|
10
|
+
- CI: Migrate release-gem.yml from actions/create-release to gh release create
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
## [v1.1.18] - 2026-05-10
|
|
14
|
+
|
|
15
|
+
- Support WebAssembly
|
|
16
|
+
- Disable auto-GC on WASM to avoid mid-draw Asyncify yield
|
|
17
|
+
- Lazy-load net/http and disable HTTP fetch on WASM
|
|
18
|
+
- Skip tmpdir cleanup on WASM
|
|
19
|
+
|
|
20
|
+
|
|
4
21
|
## [v1.1.17] - 2026-04-17
|
|
5
22
|
|
|
6
23
|
- Update dependencies
|
data/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Processing for CRuby - Processing
|
|
1
|
+
# Processing for CRuby - A Processing-compatible creative coding framework
|
|
2
2
|
|
|
3
3
|
[](https://deepwiki.com/xord/processing)
|
|
4
4
|

|
|
@@ -21,18 +21,28 @@ Thanks for your support! 🙌
|
|
|
21
21
|
|
|
22
22
|
## 🚀 About
|
|
23
23
|
|
|
24
|
-
**Processing for CRuby** is
|
|
24
|
+
**Processing for CRuby** is an independent, OpenGL-based Ruby implementation of the [Processing](https://processing.org/) API. It is **not** affiliated with the original Processing project, and it is not the JRuby / JOGL-based [`ruby-processing`](https://github.com/jashkenas/ruby-processing) either — this gem runs on CRuby (MRI), and all rendering goes through the `xord/*` family's own OpenGL 2D drawing engine ([Rays](https://github.com/xord/rays), via [Reflex](https://github.com/xord/reflex)).
|
|
25
25
|
|
|
26
|
-
|
|
26
|
+
Write a `setup do ... end` and a `draw do ... end` at the top of a Ruby file, run it, and a window appears — just like a `.pde` sketch. This gem is the thin, pure-Ruby layer that maps Processing's vocabulary onto the underlying engine (windowing, drawing, input, MIDI, camera, physics).
|
|
27
|
+
|
|
28
|
+
> Looking for the same API on mobile / with a game-engine flavor? See [RubySketch](https://github.com/xord/rubysketch).
|
|
29
|
+
|
|
30
|
+
## 📋 Requirements
|
|
31
|
+
|
|
32
|
+
- Ruby **3.0.0** or later
|
|
33
|
+
- All the runtime requirements of [Reflex](https://github.com/xord/reflex) (which in turn brings Rays, Rucy, Xot, plus the platform GUI backend — AppKit / UIKit / Win32 / SDL2 — and OpenGL)
|
|
34
|
+
- The dependent gems are installed automatically: `rexml`, `xot`, `rucy`, `rays`, `reflexion`
|
|
35
|
+
|
|
36
|
+
There is no native C/C++ extension in this gem; the heavy lifting is done by the dependencies' extensions.
|
|
27
37
|
|
|
28
38
|
## 📦 Installation
|
|
29
39
|
|
|
30
40
|
Add this line to your Gemfile:
|
|
31
41
|
```ruby
|
|
32
|
-
|
|
42
|
+
gem 'processing'
|
|
33
43
|
```
|
|
34
44
|
|
|
35
|
-
Then
|
|
45
|
+
Then install:
|
|
36
46
|
```bash
|
|
37
47
|
$ bundle install
|
|
38
48
|
```
|
|
@@ -42,7 +52,178 @@ Or install it directly:
|
|
|
42
52
|
$ gem install processing
|
|
43
53
|
```
|
|
44
54
|
|
|
55
|
+
## 📚 What's Provided
|
|
56
|
+
|
|
57
|
+
`require 'processing'` exposes a `Processing` module that, when activated, makes the Processing API available as top-level methods inside the current file. There are two ways to activate it.
|
|
58
|
+
|
|
59
|
+
### Two ways to use the gem
|
|
60
|
+
|
|
61
|
+
| Style | How |
|
|
62
|
+
| ------------------------------ | ----------------------------------------------------------------------------------------- |
|
|
63
|
+
| **Refinement, camelCase** | `require 'processing'` + `using Processing` — the standard, Processing-compatible style |
|
|
64
|
+
| **Refinement, snake_case too** | `require 'processing'` + `using Processing(snake_case: true)` — adds Ruby-idiomatic aliases (`color_mode`, `ellipse_mode`, ...) alongside the camelCase originals |
|
|
65
|
+
|
|
66
|
+
In both cases, the framework opens a window for you and runs the sketch automatically when the file exits. You do not need an explicit `start` call.
|
|
67
|
+
|
|
68
|
+
### Core API
|
|
69
|
+
|
|
70
|
+
| Area | Examples |
|
|
71
|
+
| ----------------- | --------------------------------------------------------------------------------------------------- |
|
|
72
|
+
| Sketch lifecycle | `setup`, `draw`, `windowResized`, `windowMoved` |
|
|
73
|
+
| State | `size`, `frameRate`, `frameCount`, `width`, `height`, `pixelDensity`, `noLoop` / `loop_` / `redraw` |
|
|
74
|
+
| Color & state | `background`, `fill`, `stroke`, `noFill`, `noStroke`, `strokeWeight`, `colorMode`, `blendMode` |
|
|
75
|
+
| Shapes | `point`, `line`, `rect`, `square`, `triangle`, `quad`, `ellipse`, `circle`, `arc`, `curve`, `bezier`, `beginShape` / `endShape` / `vertex` |
|
|
76
|
+
| Transforms | `push` / `pop`, `pushMatrix` / `popMatrix`, `translate`, `rotate`, `scale`, `shearX`, `shearY` |
|
|
77
|
+
| Text | `text`, `textSize`, `textFont`, `textAlign`, `textWidth`, `loadFont` |
|
|
78
|
+
| Images | `image`, `loadImage` (file path *or* URL), `createImage`, `tint`, `noTint` |
|
|
79
|
+
| Vectors & math | `PVector`, `createVector`, `random`, `noise`, `map`, `lerp`, `dist`, `radians`, `degrees` |
|
|
80
|
+
| Input | `mousePressed`, `mouseReleased`, `mouseMoved`, `mouseDragged`, `mouseClicked`, `doubleClicked`, `mouseWheel`, `keyPressed`, `keyReleased`, `keyTyped`, `touchStarted` / `touchEnded` / `touchMoved`, `motion` |
|
|
81
|
+
| Live state | `mouseX`, `mouseY`, `pmouseX`, `pmouseY`, `key`, `keyCode`, `touches` |
|
|
82
|
+
| Off-screen buffer | `createGraphics` → a `Graphics` object that shares the same drawing API |
|
|
83
|
+
| Shapes / SVG | `createShape`, `loadShape` (SVG) |
|
|
84
|
+
| Shaders | `loadShader`, `shader`, `resetShader` — GLSL shaders go straight to the OpenGL pipeline |
|
|
85
|
+
| Camera | `createCapture` — live camera capture via `Rays::Camera` |
|
|
86
|
+
|
|
87
|
+
### Top-level constants
|
|
88
|
+
|
|
89
|
+
The familiar Processing constants are defined: `RGB`, `HSB`, `RADIANS`, `DEGREES`, `CORNER`, `CORNERS`, `CENTER`, `RADIUS`, `LEFT`, `RIGHT`, `TOP`, `BOTTOM`, `BASELINE`, `BLEND`, `ADD`, `MULTIPLY`, `SCREEN`, ...
|
|
90
|
+
|
|
91
|
+
### Internal API convention
|
|
92
|
+
|
|
93
|
+
Methods ending in `__` (e.g. `init__`, `beginDraw__`, `@context__`) are framework internals and are deliberately excluded from the refinement-exposed top-level method set, so they will not collide with names in your sketch.
|
|
94
|
+
|
|
95
|
+
## 💡 Usage
|
|
96
|
+
|
|
97
|
+
### Hello, world
|
|
98
|
+
|
|
99
|
+
```ruby
|
|
100
|
+
require 'processing'
|
|
101
|
+
using Processing
|
|
102
|
+
|
|
103
|
+
draw do
|
|
104
|
+
background 0, 10 # alpha trail
|
|
105
|
+
textSize 50
|
|
106
|
+
text 'hello, world!', mouseX, mouseY
|
|
107
|
+
end
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
Save as `hello.rb`, then `ruby hello.rb`. A 500 × 500 window opens automatically.
|
|
111
|
+
|
|
112
|
+
### `setup` and `draw`
|
|
113
|
+
|
|
114
|
+
```ruby
|
|
115
|
+
require 'processing'
|
|
116
|
+
using Processing
|
|
117
|
+
|
|
118
|
+
setup do
|
|
119
|
+
size 600, 400
|
|
120
|
+
colorMode RGB, 1
|
|
121
|
+
angleMode DEGREES
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
draw do
|
|
125
|
+
background 0
|
|
126
|
+
fill 1, 0.4, 0.1
|
|
127
|
+
stroke 1
|
|
128
|
+
strokeWeight 2
|
|
129
|
+
|
|
130
|
+
rectMode CENTER
|
|
131
|
+
push
|
|
132
|
+
translate width / 2, height / 2
|
|
133
|
+
rotate frameCount # one degree per frame
|
|
134
|
+
rect 0, 0, 200, 120, 12
|
|
135
|
+
pop
|
|
136
|
+
end
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
### Loading an image from a URL
|
|
140
|
+
|
|
141
|
+
```ruby
|
|
142
|
+
require 'processing'
|
|
143
|
+
using Processing
|
|
144
|
+
|
|
145
|
+
icon = loadImage 'https://xord.org/rubysketch/images/rubysketch128.png'
|
|
146
|
+
|
|
147
|
+
draw do
|
|
148
|
+
background 0, 10
|
|
149
|
+
image icon, mouseX, mouseY, icon.width / 10, icon.height / 10
|
|
150
|
+
end
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
### Mouse and keyboard input
|
|
154
|
+
|
|
155
|
+
```ruby
|
|
156
|
+
require 'processing'
|
|
157
|
+
using Processing
|
|
158
|
+
|
|
159
|
+
setup { background 0 }
|
|
160
|
+
|
|
161
|
+
draw do
|
|
162
|
+
fill 1
|
|
163
|
+
ellipse mouseX, mouseY, 20, 20
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
mousePressed { background 0 }
|
|
167
|
+
keyPressed { puts "pressed: #{key.inspect} (#{keyCode})" }
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
### Snake_case aliases
|
|
171
|
+
|
|
172
|
+
```ruby
|
|
173
|
+
require 'processing'
|
|
174
|
+
using Processing(snake_case: true)
|
|
175
|
+
|
|
176
|
+
draw do
|
|
177
|
+
background 0
|
|
178
|
+
fill 1
|
|
179
|
+
stroke_weight 4 # alias of strokeWeight
|
|
180
|
+
no_fill # alias of noFill
|
|
181
|
+
ellipse mouse_x, mouse_y, 50, 50
|
|
182
|
+
end
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
### Off-screen rendering with `createGraphics`
|
|
186
|
+
|
|
187
|
+
```ruby
|
|
188
|
+
require 'processing'
|
|
189
|
+
using Processing
|
|
190
|
+
|
|
191
|
+
g = nil
|
|
192
|
+
|
|
193
|
+
setup do
|
|
194
|
+
size 400, 400
|
|
195
|
+
g = createGraphics 200, 200
|
|
196
|
+
g.beginDraw
|
|
197
|
+
g.background 0, 100, 200
|
|
198
|
+
g.fill 255
|
|
199
|
+
g.ellipse 100, 100, 120, 120
|
|
200
|
+
g.endDraw
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
draw do
|
|
204
|
+
background 0
|
|
205
|
+
image g, mouseX - 100, mouseY - 100
|
|
206
|
+
end
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
More examples live in [`examples/`](./examples) — `breakout.rb`, `camera.rb`, `clock.rb`, `delay_camera.rb`, `filter.rb`, `image.rb`, `shake.rb`, `shapes.rb`.
|
|
210
|
+
|
|
211
|
+
## 🛠️ Development
|
|
212
|
+
|
|
213
|
+
```bash
|
|
214
|
+
$ rake test # run the test suite (drawing tests run headless by default)
|
|
215
|
+
$ rake test:draw # run drawing tests only
|
|
216
|
+
$ rake doc # generate YARD docs
|
|
217
|
+
$ rake # default tasks
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
Visual regression tests can be enabled with `TEST_WITH_BROWSER=1` — the suite then drives [Ferrum](https://github.com/rubycdp/ferrum) to capture browser-rendered screenshots and compare them against the gem's output.
|
|
221
|
+
|
|
222
|
+
In the [`xord/all`](https://github.com/xord/all) monorepo you can scope by module, e.g. `rake processing test`.
|
|
223
|
+
|
|
45
224
|
## 📜 License
|
|
46
225
|
|
|
47
226
|
**Processing for CRuby** is licensed under the MIT License.
|
|
48
227
|
See the [LICENSE](./LICENSE) file for details.
|
|
228
|
+
|
|
229
|
+
This project is not affiliated with [Processing.org](https://processing.org/); it is an independent reimplementation of their API.
|
data/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
1.
|
|
1
|
+
1.2.0
|
data/lib/processing/all.rb
CHANGED
data/lib/processing/capture.rb
CHANGED
|
@@ -108,11 +108,15 @@ module Processing
|
|
|
108
108
|
end
|
|
109
109
|
|
|
110
110
|
# @private
|
|
111
|
-
def drawImage__(painter, *args
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
painter.
|
|
111
|
+
def drawImage__(painter, *args)
|
|
112
|
+
if @filter
|
|
113
|
+
shader = painter.shader
|
|
114
|
+
painter.shader = @filter.getInternal__
|
|
115
115
|
end
|
|
116
|
+
painter.image getInternal__, *args
|
|
117
|
+
nil
|
|
118
|
+
ensure
|
|
119
|
+
painter.shader = shader if @filter
|
|
116
120
|
end
|
|
117
121
|
|
|
118
122
|
end# Capture
|
data/lib/processing/context.rb
CHANGED
data/lib/processing/extension.rb
CHANGED
|
@@ -1835,8 +1835,14 @@ module Processing
|
|
|
1835
1835
|
def image(img, a, b, c = nil, d = nil)
|
|
1836
1836
|
assertDrawing__
|
|
1837
1837
|
x, y, w, h = toXYWH__ @imageMode__, a, b, c || img.width, d || img.height
|
|
1838
|
-
|
|
1839
|
-
|
|
1838
|
+
fill = @painter__.fill
|
|
1839
|
+
begin
|
|
1840
|
+
@painter__.fill = getTint__
|
|
1841
|
+
img.drawImage__ @painter__, x, y, w, h
|
|
1842
|
+
nil
|
|
1843
|
+
ensure
|
|
1844
|
+
@painter__.fill = fill
|
|
1845
|
+
end
|
|
1840
1846
|
end
|
|
1841
1847
|
|
|
1842
1848
|
alias drawImage image
|
|
@@ -2074,9 +2080,17 @@ module Processing
|
|
|
2074
2080
|
#
|
|
2075
2081
|
def blend(img = nil, sx, sy, sw, sh, dx, dy, dw, dh, mode)
|
|
2076
2082
|
assertDrawing__
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
|
|
2083
|
+
fill = @painter__.fill
|
|
2084
|
+
blend_mode = @painter__.blend_mode
|
|
2085
|
+
begin
|
|
2086
|
+
@painter__.fill = getTint__
|
|
2087
|
+
@painter__.blend_mode = mode
|
|
2088
|
+
(img || self).drawImage__(@painter__, sx, sy, sw, sh, dx, dy, dw, dh)
|
|
2089
|
+
nil
|
|
2090
|
+
ensure
|
|
2091
|
+
@painter__.fill = fill
|
|
2092
|
+
@painter__.blend_mode = blend_mode
|
|
2093
|
+
end
|
|
2080
2094
|
end
|
|
2081
2095
|
|
|
2082
2096
|
# Loads all pixels to the 'pixels' array.
|
|
@@ -2535,11 +2549,15 @@ module Processing
|
|
|
2535
2549
|
end
|
|
2536
2550
|
|
|
2537
2551
|
# @private
|
|
2538
|
-
def drawImage__(painter, *args, image__: getInternal__
|
|
2539
|
-
|
|
2540
|
-
|
|
2541
|
-
painter.
|
|
2552
|
+
def drawImage__(painter, *args, image__: getInternal__)
|
|
2553
|
+
if @filter__
|
|
2554
|
+
shader = painter.shader
|
|
2555
|
+
painter.shader = @filter__.getInternal__
|
|
2542
2556
|
end
|
|
2557
|
+
painter.image image__, *args
|
|
2558
|
+
nil
|
|
2559
|
+
ensure
|
|
2560
|
+
painter.shader = shader if @filter__
|
|
2543
2561
|
end
|
|
2544
2562
|
|
|
2545
2563
|
# @private
|
|
@@ -3449,6 +3467,8 @@ module Processing
|
|
|
3449
3467
|
path = path.sub_ext ext
|
|
3450
3468
|
|
|
3451
3469
|
unless path.file?
|
|
3470
|
+
raise NotImplementedError, 'HTTP request is not supported on WASM' if Xot.wasm?
|
|
3471
|
+
require 'net/http'
|
|
3452
3472
|
Net::HTTP.get_response URI.parse(uri) do |res|
|
|
3453
3473
|
res.value # raise an error unless successful
|
|
3454
3474
|
tmpdir.mkdir unless tmpdir.directory?
|
data/lib/processing/image.rb
CHANGED
|
@@ -200,7 +200,13 @@ module Processing
|
|
|
200
200
|
def blend(img = nil, sx, sy, sw, sh, dx, dy, dw, dh, mode)
|
|
201
201
|
img ||= self
|
|
202
202
|
getInternal__.paint do |painter|
|
|
203
|
-
|
|
203
|
+
blend_mode = painter.blend_mode
|
|
204
|
+
begin
|
|
205
|
+
painter.blend_mode = mode
|
|
206
|
+
img.drawImage__ painter, sx, sy, sw, sh, dx, dy, dw, dh
|
|
207
|
+
ensure
|
|
208
|
+
painter.blend_mode = blend_mode
|
|
209
|
+
end
|
|
204
210
|
end
|
|
205
211
|
nil
|
|
206
212
|
end
|
|
@@ -270,11 +276,15 @@ module Processing
|
|
|
270
276
|
end
|
|
271
277
|
|
|
272
278
|
# @private
|
|
273
|
-
def drawImage__(painter, *args
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
painter.
|
|
279
|
+
def drawImage__(painter, *args)
|
|
280
|
+
if @filter
|
|
281
|
+
shader = painter.shader
|
|
282
|
+
painter.shader = @filter.getInternal__
|
|
277
283
|
end
|
|
284
|
+
painter.image getInternal__, *args
|
|
285
|
+
nil
|
|
286
|
+
ensure
|
|
287
|
+
painter.shader = shader if @filter
|
|
278
288
|
end
|
|
279
289
|
|
|
280
290
|
# @private
|
data/lib/processing/shader.rb
CHANGED
|
@@ -71,15 +71,17 @@ module Processing
|
|
|
71
71
|
ENV__ = {
|
|
72
72
|
attribute_position: [:vertex, :position],
|
|
73
73
|
attribute_texcoord: :texCoord,
|
|
74
|
+
attribute_texcoord_min: :texCoordMin,
|
|
75
|
+
attribute_texcoord_max: :texCoordMax,
|
|
74
76
|
attribute_color: :color,
|
|
75
77
|
varying_position: :vertPosition,
|
|
76
78
|
varying_texcoord: :vertTexCoord,
|
|
79
|
+
varying_texcoord_min: :vertTexCoordMin,
|
|
80
|
+
varying_texcoord_max: :vertTexCoordMax,
|
|
77
81
|
varying_color: :vertColor,
|
|
78
82
|
uniform_position_matrix: [:transform, :transformMatrix],
|
|
79
83
|
uniform_texcoord_matrix: :texMatrix,
|
|
80
|
-
|
|
81
|
-
uniform_texcoord_max: :texMax,
|
|
82
|
-
uniform_texcoord_offset: :texOffset,
|
|
84
|
+
uniform_texcoord_pixel: :texOffset,
|
|
83
85
|
uniform_texture: [:texMap, :texture]
|
|
84
86
|
}.freeze
|
|
85
87
|
|
|
@@ -144,10 +146,10 @@ module Processing
|
|
|
144
146
|
#define PI 3.1415926538
|
|
145
147
|
uniform float radius;
|
|
146
148
|
uniform sampler2D texMap;
|
|
147
|
-
uniform vec3 texMin;
|
|
148
|
-
uniform vec3 texMax;
|
|
149
149
|
uniform vec3 texOffset;
|
|
150
150
|
varying vec4 vertTexCoord;
|
|
151
|
+
varying vec3 vertTexCoordMin;
|
|
152
|
+
varying vec3 vertTexCoordMax;
|
|
151
153
|
varying vec4 vertColor;
|
|
152
154
|
float gaussian(vec2 pos, float sigma) {
|
|
153
155
|
float s2 = sigma * sigma;
|
|
@@ -163,8 +165,8 @@ module Processing
|
|
|
163
165
|
float weight = gaussian(offset, sigma);
|
|
164
166
|
vec2 texcoord = vertTexCoord.xy + offset * texOffset.xy;
|
|
165
167
|
if (
|
|
166
|
-
texcoord.x <
|
|
167
|
-
texcoord.y <
|
|
168
|
+
texcoord.x < vertTexCoordMin.x || vertTexCoordMax.x < texcoord.x ||
|
|
169
|
+
texcoord.y < vertTexCoordMin.y || vertTexCoordMax.y < texcoord.y
|
|
168
170
|
) continue;
|
|
169
171
|
color += texture2D(texMap, texcoord).rgb * weight;
|
|
170
172
|
total_weight += weight;
|
data/lib/processing/window.rb
CHANGED
|
@@ -17,6 +17,11 @@ module Processing
|
|
|
17
17
|
@canvas_view = add CanvasView.new name: :canvas
|
|
18
18
|
@overlay_view = @canvas_view.add Reflex::View.new name: :overlay
|
|
19
19
|
|
|
20
|
+
# On WASM, auto-GC may yield mid-draw via Asyncify and cause partial
|
|
21
|
+
# frames to be presented. Disable auto-GC and run GC.start manually
|
|
22
|
+
# at a safe point (on_canvas_update) to avoid this.
|
|
23
|
+
GC.disable if Xot.wasm?
|
|
24
|
+
|
|
20
25
|
super(*args, size: [width, height], **kwargs, &block)
|
|
21
26
|
|
|
22
27
|
self.center = screen.center
|
|
@@ -101,6 +106,7 @@ module Processing
|
|
|
101
106
|
def on_canvas_update(e)
|
|
102
107
|
call_block @update, e
|
|
103
108
|
@canvas_view.redraw
|
|
109
|
+
GC.start if Xot.wasm? # explicit GC at a safe point (no draw in progress)
|
|
104
110
|
end
|
|
105
111
|
|
|
106
112
|
def on_canvas_draw(e)
|
data/processing.gemspec
CHANGED
|
@@ -10,7 +10,7 @@ Gem::Specification.new do |s|
|
|
|
10
10
|
end
|
|
11
11
|
|
|
12
12
|
ext = Processing::Extension
|
|
13
|
-
name = ext.name
|
|
13
|
+
name = ext.name true
|
|
14
14
|
rdocs = glob.call *%w[README]
|
|
15
15
|
|
|
16
16
|
s.name = name
|
|
@@ -26,10 +26,10 @@ Gem::Specification.new do |s|
|
|
|
26
26
|
s.required_ruby_version = '>= 3.0.0'
|
|
27
27
|
|
|
28
28
|
s.add_dependency 'rexml'
|
|
29
|
-
s.add_dependency 'xot', '~> 0.3.
|
|
30
|
-
s.add_dependency 'rucy', '~> 0.3.
|
|
31
|
-
s.add_dependency 'rays', '~> 0.3.
|
|
32
|
-
s.add_dependency 'reflexion', '~> 0.
|
|
29
|
+
s.add_dependency 'xot', '~> 0.3.13'
|
|
30
|
+
s.add_dependency 'rucy', '~> 0.3.13'
|
|
31
|
+
s.add_dependency 'rays', '~> 0.3.13'
|
|
32
|
+
s.add_dependency 'reflexion', '~> 0.4.0'
|
|
33
33
|
|
|
34
34
|
s.files = `git ls-files`.split $/
|
|
35
35
|
s.test_files = s.files.grep %r{^(test|spec|features)/}
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: processing
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.
|
|
4
|
+
version: 1.2.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- xordog
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-
|
|
11
|
+
date: 2026-05-16 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rexml
|
|
@@ -30,56 +30,56 @@ dependencies:
|
|
|
30
30
|
requirements:
|
|
31
31
|
- - "~>"
|
|
32
32
|
- !ruby/object:Gem::Version
|
|
33
|
-
version: 0.3.
|
|
33
|
+
version: 0.3.13
|
|
34
34
|
type: :runtime
|
|
35
35
|
prerelease: false
|
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
|
37
37
|
requirements:
|
|
38
38
|
- - "~>"
|
|
39
39
|
- !ruby/object:Gem::Version
|
|
40
|
-
version: 0.3.
|
|
40
|
+
version: 0.3.13
|
|
41
41
|
- !ruby/object:Gem::Dependency
|
|
42
42
|
name: rucy
|
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
|
44
44
|
requirements:
|
|
45
45
|
- - "~>"
|
|
46
46
|
- !ruby/object:Gem::Version
|
|
47
|
-
version: 0.3.
|
|
47
|
+
version: 0.3.13
|
|
48
48
|
type: :runtime
|
|
49
49
|
prerelease: false
|
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
|
51
51
|
requirements:
|
|
52
52
|
- - "~>"
|
|
53
53
|
- !ruby/object:Gem::Version
|
|
54
|
-
version: 0.3.
|
|
54
|
+
version: 0.3.13
|
|
55
55
|
- !ruby/object:Gem::Dependency
|
|
56
56
|
name: rays
|
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
|
58
58
|
requirements:
|
|
59
59
|
- - "~>"
|
|
60
60
|
- !ruby/object:Gem::Version
|
|
61
|
-
version: 0.3.
|
|
61
|
+
version: 0.3.13
|
|
62
62
|
type: :runtime
|
|
63
63
|
prerelease: false
|
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
|
65
65
|
requirements:
|
|
66
66
|
- - "~>"
|
|
67
67
|
- !ruby/object:Gem::Version
|
|
68
|
-
version: 0.3.
|
|
68
|
+
version: 0.3.13
|
|
69
69
|
- !ruby/object:Gem::Dependency
|
|
70
70
|
name: reflexion
|
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
|
72
72
|
requirements:
|
|
73
73
|
- - "~>"
|
|
74
74
|
- !ruby/object:Gem::Version
|
|
75
|
-
version: 0.
|
|
75
|
+
version: 0.4.0
|
|
76
76
|
type: :runtime
|
|
77
77
|
prerelease: false
|
|
78
78
|
version_requirements: !ruby/object:Gem::Requirement
|
|
79
79
|
requirements:
|
|
80
80
|
- - "~>"
|
|
81
81
|
- !ruby/object:Gem::Version
|
|
82
|
-
version: 0.
|
|
82
|
+
version: 0.4.0
|
|
83
83
|
description: Creative Coding Framework has API compatible to Processing or p5.js.
|
|
84
84
|
email: xordog@gmail.com
|
|
85
85
|
executables: []
|