reight 0.1.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 +7 -0
- data/.github/workflows/release-gem.yml +62 -0
- data/.github/workflows/tag.yml +35 -0
- data/.github/workflows/test.yml +37 -0
- data/.github/workflows/utils.rb +56 -0
- data/.gitignore +1 -0
- data/ChangeLog.md +23 -0
- data/Gemfile +6 -0
- data/LICENSE +21 -0
- data/README.md +62 -0
- data/Rakefile +30 -0
- data/VERSION +1 -0
- data/bin/r8 +35 -0
- data/lib/reight/all.rb +59 -0
- data/lib/reight/app/map/brush.rb +27 -0
- data/lib/reight/app/map/brush_base.rb +54 -0
- data/lib/reight/app/map/canvas.rb +150 -0
- data/lib/reight/app/map/chips.rb +84 -0
- data/lib/reight/app/map/editor.rb +117 -0
- data/lib/reight/app/map/line.rb +35 -0
- data/lib/reight/app/map/rect.rb +29 -0
- data/lib/reight/app/map/tool.rb +32 -0
- data/lib/reight/app/map.rb +8 -0
- data/lib/reight/app/music/editor.rb +25 -0
- data/lib/reight/app/music.rb +1 -0
- data/lib/reight/app/navigator.rb +172 -0
- data/lib/reight/app/runner.rb +275 -0
- data/lib/reight/app/sound/editor.rb +25 -0
- data/lib/reight/app/sound.rb +1 -0
- data/lib/reight/app/sprite/brush.rb +43 -0
- data/lib/reight/app/sprite/canvas.rb +254 -0
- data/lib/reight/app/sprite/chips.rb +92 -0
- data/lib/reight/app/sprite/color.rb +30 -0
- data/lib/reight/app/sprite/editor.rb +272 -0
- data/lib/reight/app/sprite/fill.rb +45 -0
- data/lib/reight/app/sprite/line.rb +37 -0
- data/lib/reight/app/sprite/select.rb +58 -0
- data/lib/reight/app/sprite/shape.rb +43 -0
- data/lib/reight/app/sprite/tool.rb +27 -0
- data/lib/reight/app/sprite.rb +10 -0
- data/lib/reight/app.rb +123 -0
- data/lib/reight/button.rb +93 -0
- data/lib/reight/chip.rb +150 -0
- data/lib/reight/extension.rb +24 -0
- data/lib/reight/helpers.rb +69 -0
- data/lib/reight/history.rb +135 -0
- data/lib/reight/map.rb +264 -0
- data/lib/reight/project.rb +115 -0
- data/lib/reight/reight.rb +83 -0
- data/lib/reight.rb +18 -0
- data/reight.gemspec +40 -0
- data/res/icons.png +0 -0
- data/test/helper.rb +15 -0
- data/test/test_chip.rb +108 -0
- data/test/test_chip_list.rb +68 -0
- data/test/test_map.rb +232 -0
- data/test/test_map_chunk.rb +226 -0
- metadata +244 -0
@@ -0,0 +1,275 @@
|
|
1
|
+
using Reight
|
2
|
+
|
3
|
+
|
4
|
+
class Reight::Runner < Reight::App
|
5
|
+
|
6
|
+
TEMPORARY_HASH = {}
|
7
|
+
|
8
|
+
def activated()
|
9
|
+
super
|
10
|
+
run force: true
|
11
|
+
@context.call_activated__
|
12
|
+
end
|
13
|
+
|
14
|
+
def deactivated()
|
15
|
+
super
|
16
|
+
@context.call_deactivated__
|
17
|
+
pause
|
18
|
+
end
|
19
|
+
|
20
|
+
def draw()
|
21
|
+
push do
|
22
|
+
@context&.call_draw__ unless paused?
|
23
|
+
end
|
24
|
+
super
|
25
|
+
end
|
26
|
+
|
27
|
+
def key_pressed()
|
28
|
+
super
|
29
|
+
@context&.key_pressed unless paused?
|
30
|
+
end
|
31
|
+
|
32
|
+
def key_released()
|
33
|
+
super
|
34
|
+
@context&.key_released unless paused?
|
35
|
+
end
|
36
|
+
|
37
|
+
def key_typed()
|
38
|
+
super
|
39
|
+
@context&.key_typed unless paused?
|
40
|
+
end
|
41
|
+
|
42
|
+
def mouse_pressed()
|
43
|
+
super
|
44
|
+
@context&.mouse_pressed unless paused?
|
45
|
+
end
|
46
|
+
|
47
|
+
def mouse_released()
|
48
|
+
super
|
49
|
+
@context&.mouse_released unless paused?
|
50
|
+
end
|
51
|
+
|
52
|
+
def mouse_moved()
|
53
|
+
super
|
54
|
+
@context&.mouse_moved unless paused?
|
55
|
+
navigator.visible = mouse_y < NAVIGATOR_HEIGHT
|
56
|
+
end
|
57
|
+
|
58
|
+
def mouse_dragged()
|
59
|
+
super
|
60
|
+
@context&.mouse_dragged unless paused?
|
61
|
+
end
|
62
|
+
|
63
|
+
def mouse_clicked()
|
64
|
+
super
|
65
|
+
@context&.mouse_clicked unless paused?
|
66
|
+
end
|
67
|
+
|
68
|
+
def double_clicked()
|
69
|
+
super
|
70
|
+
@context&.double_clicked unless paused?
|
71
|
+
end
|
72
|
+
|
73
|
+
def mouse_wheel()
|
74
|
+
super
|
75
|
+
@context&.mouse_wheel unless paused?
|
76
|
+
end
|
77
|
+
|
78
|
+
def touch_started()
|
79
|
+
super
|
80
|
+
@context&.touch_started unless paused?
|
81
|
+
end
|
82
|
+
|
83
|
+
def touch_ended()
|
84
|
+
super
|
85
|
+
@context&.touch_ended unless paused?
|
86
|
+
end
|
87
|
+
|
88
|
+
def touch_moved()
|
89
|
+
super
|
90
|
+
@context&.touch_moved unless paused?
|
91
|
+
end
|
92
|
+
|
93
|
+
def window_moved()
|
94
|
+
super
|
95
|
+
@context&.window_moved
|
96
|
+
end
|
97
|
+
|
98
|
+
def window_resized()
|
99
|
+
super
|
100
|
+
@context&.window_resized
|
101
|
+
end
|
102
|
+
|
103
|
+
private
|
104
|
+
|
105
|
+
def running? = @context && !@paused
|
106
|
+
|
107
|
+
def paused? = @context && @paused
|
108
|
+
|
109
|
+
def run(force: false)
|
110
|
+
return pause false if paused? && !force
|
111
|
+
cleanup
|
112
|
+
backup_global_vars
|
113
|
+
@context = create_context
|
114
|
+
@paused = false
|
115
|
+
begin_wrapping_user_classes @context
|
116
|
+
eval_user_script @context, project.code_paths.zip(project.codes).to_h
|
117
|
+
end
|
118
|
+
|
119
|
+
def pause(state = true)
|
120
|
+
@paused = state
|
121
|
+
end
|
122
|
+
|
123
|
+
def cleanup()
|
124
|
+
remove_world @context.sprite_world__ if @context
|
125
|
+
@context = nil
|
126
|
+
end_wrapping_user_classes
|
127
|
+
restore_global_vars
|
128
|
+
GC.enable
|
129
|
+
GC.start
|
130
|
+
end
|
131
|
+
|
132
|
+
def create_context()
|
133
|
+
klass = Class.new do
|
134
|
+
def project = @project__
|
135
|
+
|
136
|
+
def sprite_world__ = @sprite_world__ ||= create_world(pixels_per_meter: 5)
|
137
|
+
|
138
|
+
def call_activated__()
|
139
|
+
add_world sprite_world__
|
140
|
+
activated
|
141
|
+
end
|
142
|
+
|
143
|
+
def call_deactivated__()
|
144
|
+
deactivated
|
145
|
+
remove_world sprite_world__
|
146
|
+
@background_cleared__ = false
|
147
|
+
end
|
148
|
+
|
149
|
+
def call_draw__()
|
150
|
+
unless @setup_done__
|
151
|
+
@setup_done__ = true
|
152
|
+
setup
|
153
|
+
end
|
154
|
+
unless @background_cleared__
|
155
|
+
@background_cleared__ = true
|
156
|
+
background 100, 100, 100
|
157
|
+
end
|
158
|
+
draw
|
159
|
+
end
|
160
|
+
|
161
|
+
def createSprite(...) = sprite_world__.createSprite(...)
|
162
|
+
def addSprite(...) = sprite_world__.addSprite(...)
|
163
|
+
def removeSprite(...) = sprite_world__.removeSprite(...)
|
164
|
+
def gravity(...) = sprite_world__.gravity(...)
|
165
|
+
end
|
166
|
+
Reight.to_snake_case(%i[
|
167
|
+
activated deactivated setup draw
|
168
|
+
keyPressed keyReleased keyRyped
|
169
|
+
mousePressed mouseReleased mouseMoved mouseDragged
|
170
|
+
mouseClicked doubleClicked mouseWheel
|
171
|
+
touchStarted touchEnded touchMoved
|
172
|
+
windowMoved windowResized
|
173
|
+
]).each do |camel, snake|
|
174
|
+
klass.class_eval <<~END
|
175
|
+
def #{camel}(&block)
|
176
|
+
if block
|
177
|
+
@#{camel}_block__ = block
|
178
|
+
else
|
179
|
+
@#{camel}_block__&.call
|
180
|
+
end
|
181
|
+
end
|
182
|
+
END
|
183
|
+
klass.alias_method snake, camel if snake != camel
|
184
|
+
end
|
185
|
+
klass.new.tap do |context|
|
186
|
+
context.instance_variable_set :@project__, project
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
def begin_wrapping_user_classes(context)
|
191
|
+
prefix = get_user_class_prefix context
|
192
|
+
wrapper = create_user_class_wrapper context
|
193
|
+
@trace_point = TracePoint.trace :class do |tp|
|
194
|
+
tp.self.include wrapper if tp.self.name&.start_with? prefix
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
def end_wrapping_user_classes()
|
199
|
+
@trace_point&.disable
|
200
|
+
@trace_point = nil
|
201
|
+
end
|
202
|
+
|
203
|
+
def get_user_class_prefix(context)
|
204
|
+
prefix = nil
|
205
|
+
context.instance_eval <<~EVAL
|
206
|
+
class Reight_Dummy__; end
|
207
|
+
prefix = Reight_Dummy__.name[/^#<Class:0x[0-9a-zA-Z]+>::/]
|
208
|
+
singleton_class.__send__ :remove_const, :Reight_Dummy__
|
209
|
+
EVAL
|
210
|
+
prefix
|
211
|
+
end
|
212
|
+
|
213
|
+
def create_user_class_wrapper(context)
|
214
|
+
Module.new.tap do |wrapper|
|
215
|
+
wrap_methods context, wrapper
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
def wrap_methods(context, klass)
|
220
|
+
klass.define_method :respond_to_missing? do |name, include_private = false|
|
221
|
+
context.respond_to?(name, false) || super(name, include_private)
|
222
|
+
end
|
223
|
+
klass.define_method :method_missing do |name, *args, **kwargs, &block|
|
224
|
+
if context.respond_to? name
|
225
|
+
klass.define_method(name) {|*a, **k, &b| context.public_send name, *a, **k, &b}
|
226
|
+
context.public_send name, *args, **kwargs, &block
|
227
|
+
else
|
228
|
+
super name, *args, **kwargs, &block
|
229
|
+
end
|
230
|
+
end
|
231
|
+
Reight.to_snake_case(%i[
|
232
|
+
project createSprite addSprite removeSprite gravity
|
233
|
+
]).each do |camel, snake|
|
234
|
+
klass.define_method(camel) {|*a, **k, &b| context.public_send camel, *a, **k, &b}
|
235
|
+
klass.alias_method snake, camel if snake != camel
|
236
|
+
end
|
237
|
+
end
|
238
|
+
|
239
|
+
def eval_user_script(context, codes)
|
240
|
+
TEMPORARY_HASH[:params] = {context: context, codes: codes}
|
241
|
+
context.class.class_eval <<~END
|
242
|
+
::Reight::Runner::TEMPORARY_HASH[:params] => {context:, codes:}
|
243
|
+
codes.each {|path, code| context.instance_eval code, path if code}
|
244
|
+
END
|
245
|
+
ensure
|
246
|
+
TEMPORARY_HASH.delete :params
|
247
|
+
end
|
248
|
+
|
249
|
+
def backup_global_vars()
|
250
|
+
@global_vars = global_variables
|
251
|
+
.each.with_object({}) {|name, hash| hash[name] = eval name.to_s}
|
252
|
+
.freeze
|
253
|
+
end
|
254
|
+
|
255
|
+
def restore_global_vars()
|
256
|
+
return unless @global_vars
|
257
|
+
global_variables
|
258
|
+
.map {|name| [name, eval(name.to_s)]}
|
259
|
+
.select {|name, value| value != nil && @global_vars[name] == nil}
|
260
|
+
.each {|name, value| global_var_set name, nil}
|
261
|
+
%i[$, $/ $-0 $; $-F $-d $-i $-v $-w $. $\\ $_ $~ $DEBUG $VERBOSE]
|
262
|
+
.select {|name| @global_vars.key? name}
|
263
|
+
.each {|name| global_var_set name, @global_vars[name]}
|
264
|
+
/x/ =~ '' # clear vars about last result for regexp
|
265
|
+
@global_vars = nil
|
266
|
+
end
|
267
|
+
|
268
|
+
def global_var_set(name, value)
|
269
|
+
TEMPORARY_HASH[:value] = value
|
270
|
+
eval "#{name} = ::Reight::Runner::TEMPORARY_HASH[:value]"
|
271
|
+
ensure
|
272
|
+
TEMPORARY_HASH.delete :value
|
273
|
+
end
|
274
|
+
|
275
|
+
end# Runner
|
@@ -0,0 +1,25 @@
|
|
1
|
+
using Reight
|
2
|
+
|
3
|
+
|
4
|
+
class Reight::SoundEditor < Reight::App
|
5
|
+
|
6
|
+
def draw()
|
7
|
+
background 200
|
8
|
+
|
9
|
+
push do
|
10
|
+
text_align LEFT, CENTER
|
11
|
+
|
12
|
+
text_size 10
|
13
|
+
fill 220; text "Sound Editor", 150, 1, 200, height
|
14
|
+
fill 150; text "Sound Editor", 150, 0, 200, height
|
15
|
+
|
16
|
+
text_size 8
|
17
|
+
dots = '.' * (frame_count / 60 % 4).to_i
|
18
|
+
fill 220; text "is under construction#{dots}", 150, 11, 200, height
|
19
|
+
fill 150; text "is under construction#{dots}", 150, 10, 200, height
|
20
|
+
end
|
21
|
+
|
22
|
+
super
|
23
|
+
end
|
24
|
+
|
25
|
+
end# SoundEditor
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'reight/app/sound/editor'
|
@@ -0,0 +1,43 @@
|
|
1
|
+
using Reight
|
2
|
+
|
3
|
+
|
4
|
+
class Reight::SpriteEditor::Brush < Reight::SpriteEditor::Tool
|
5
|
+
|
6
|
+
def initialize(app, &block)
|
7
|
+
super app, icon: app.icon(1, 2, 8), &block
|
8
|
+
@size = 1
|
9
|
+
set_help left: 'Brush', right: 'Pick Color'
|
10
|
+
end
|
11
|
+
|
12
|
+
attr_accessor :size
|
13
|
+
|
14
|
+
def brush(x, y, button)
|
15
|
+
canvas.paint do |g|
|
16
|
+
g.no_fill
|
17
|
+
g.stroke(*canvas.color)
|
18
|
+
g.stroke_weight size
|
19
|
+
g.point x, y
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def canvas_pressed(x, y, button)
|
24
|
+
return unless button == LEFT
|
25
|
+
canvas.begin_editing
|
26
|
+
brush x, y, button
|
27
|
+
end
|
28
|
+
|
29
|
+
def canvas_released(x, y, button)
|
30
|
+
return unless button == LEFT
|
31
|
+
canvas.end_editing
|
32
|
+
end
|
33
|
+
|
34
|
+
def canvas_dragged(x, y, button)
|
35
|
+
return unless button == LEFT
|
36
|
+
brush x, y, button
|
37
|
+
end
|
38
|
+
|
39
|
+
def canvas_clicked(x, y, button)
|
40
|
+
pick_color x, y if button == RIGHT
|
41
|
+
end
|
42
|
+
|
43
|
+
end# Brush
|
@@ -0,0 +1,254 @@
|
|
1
|
+
using Reight
|
2
|
+
|
3
|
+
|
4
|
+
class Reight::SpriteEditor::Canvas
|
5
|
+
|
6
|
+
include Reight::Hookable
|
7
|
+
|
8
|
+
def initialize(app, image, path)
|
9
|
+
hook :tool_changed, :color_changed
|
10
|
+
|
11
|
+
@app, @image, @path = app, image, path
|
12
|
+
@tool, @color, @selection = nil, [255, 255, 255], nil
|
13
|
+
|
14
|
+
@app.history.disable do
|
15
|
+
set_frame 0, 0, 16, 16
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
attr_reader :x, :y, :w, :h, :tool, :color
|
20
|
+
|
21
|
+
def width = @image.width
|
22
|
+
|
23
|
+
def height = @image.height
|
24
|
+
|
25
|
+
def save()
|
26
|
+
@image.save @path
|
27
|
+
@app.project.save
|
28
|
+
end
|
29
|
+
|
30
|
+
def tool=(tool)
|
31
|
+
@tool = tool
|
32
|
+
tool_changed! tool
|
33
|
+
end
|
34
|
+
|
35
|
+
def set_frame(x, y, w, h)
|
36
|
+
old = [@x, @y, @w, @h]
|
37
|
+
new = correct_bounds x, y, w, h
|
38
|
+
return if new == old
|
39
|
+
@x, @y, @w, @h = new
|
40
|
+
@app.history.append [:frame, old, new]
|
41
|
+
end
|
42
|
+
|
43
|
+
def frame = [x, y, w, h]
|
44
|
+
|
45
|
+
def color=(color)
|
46
|
+
return if color == @color
|
47
|
+
@color = color
|
48
|
+
color_changed! color
|
49
|
+
end
|
50
|
+
|
51
|
+
def select(x, y, w, h)
|
52
|
+
old = @selection
|
53
|
+
new = correct_bounds x, y, w, h
|
54
|
+
return if new == old
|
55
|
+
@selection = new
|
56
|
+
@app.history.append [:select, old, new]
|
57
|
+
end
|
58
|
+
|
59
|
+
def selection()
|
60
|
+
xrange, yrange = x..(x + w), y..(y + h)
|
61
|
+
sx, sy, sw, sh = @selection
|
62
|
+
return nil unless
|
63
|
+
xrange.include?(sx) && xrange.include?(sx + sw) &&
|
64
|
+
yrange.include?(sy) && yrange.include?(sy + sh)
|
65
|
+
@selection
|
66
|
+
end
|
67
|
+
|
68
|
+
def deselect()
|
69
|
+
return if @selection == nil
|
70
|
+
old, @selection = @selection, nil
|
71
|
+
@app.history.append [:deselect, old]
|
72
|
+
end
|
73
|
+
|
74
|
+
def paint(&block)
|
75
|
+
@image.begin_draw do |g|
|
76
|
+
g.clip(*(selection || frame))
|
77
|
+
g.push do
|
78
|
+
g.translate x, y
|
79
|
+
block.call g
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def update_pixels(&block)
|
85
|
+
tmp = sub_image x, y, w, h
|
86
|
+
tmp.update_pixels {|pixels| block.call pixels}
|
87
|
+
@image.begin_draw do |g|
|
88
|
+
g.copy tmp, 0, 0, w, h, x, y, w, h
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
def sub_image(x, y, w, h)
|
93
|
+
create_graphics(w, h).tap do |g|
|
94
|
+
g.begin_draw {g.copy @image, x, y, w, h, 0, 0, w, h}
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def pixel_at(x, y)
|
99
|
+
img = sub_image x, y, 1, 1
|
100
|
+
img.load_pixels
|
101
|
+
c = img.pixels[0]
|
102
|
+
[red(c), green(c), blue(c), alpha(c)].map &:to_i
|
103
|
+
end
|
104
|
+
|
105
|
+
def clear(frame, color: [0, 0, 0])
|
106
|
+
paint do |g|
|
107
|
+
g.fill(*color)
|
108
|
+
g.no_stroke
|
109
|
+
g.rect(*frame)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def begin_editing(&block)
|
114
|
+
@before = capture_frame
|
115
|
+
block.call if block
|
116
|
+
ensure
|
117
|
+
end_editing if block
|
118
|
+
end
|
119
|
+
|
120
|
+
def end_editing()
|
121
|
+
return unless @before
|
122
|
+
@app.history.append [:capture, @before, capture_frame, x, y]
|
123
|
+
save
|
124
|
+
end
|
125
|
+
|
126
|
+
def capture_frame(frame = self.frame)
|
127
|
+
x, y, w, h = frame
|
128
|
+
create_graphics(w, h).tap do |g|
|
129
|
+
g.begin_draw do
|
130
|
+
g.copy @image, x, y, w, h, 0, 0, w, h
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
def apply_frame(image, x, y)
|
136
|
+
@image.begin_draw do |g|
|
137
|
+
w, h = image.width, image.height
|
138
|
+
g.copy image, 0, 0, w, h, x, y, w, h
|
139
|
+
end
|
140
|
+
save
|
141
|
+
end
|
142
|
+
|
143
|
+
def sprite()
|
144
|
+
@sprite ||= Sprite.new.tap do |sp|
|
145
|
+
pos = -> {to_image sp.mouse_x, sp.mouse_y}
|
146
|
+
sp.draw {draw}
|
147
|
+
sp.mouse_pressed {tool&.canvas_pressed( *pos.call, sp.mouse_button)}
|
148
|
+
sp.mouse_released {tool&.canvas_released(*pos.call, sp.mouse_button)}
|
149
|
+
sp.mouse_moved {tool&.canvas_moved( *pos.call)}
|
150
|
+
sp.mouse_dragged {tool&.canvas_dragged( *pos.call, sp.mouse_button)}
|
151
|
+
sp.mouse_clicked {tool&.canvas_clicked( *pos.call, sp.mouse_button)}
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
private
|
156
|
+
|
157
|
+
def to_image(x, y)
|
158
|
+
return x, y unless @w && @h
|
159
|
+
sp = sprite
|
160
|
+
return x * (@w.to_f / sp.w), y * (@h.to_f / sp.h)
|
161
|
+
end
|
162
|
+
|
163
|
+
def correct_bounds(x, y, w, h)
|
164
|
+
x2, y2 = x + w, y + h
|
165
|
+
x, x2 = x2, x if x > x2
|
166
|
+
y, y2 = y2, y if y > y2
|
167
|
+
x, y = x.floor, y.floor
|
168
|
+
return x, y, (x2 - x).ceil, (y2 - y).ceil
|
169
|
+
end
|
170
|
+
|
171
|
+
def draw()
|
172
|
+
sp = sprite
|
173
|
+
clip sp.x, sp.y, sp.w, sp.h
|
174
|
+
copy @image, x, y, w, h, 0, 0, sp.w, sp.h if @image && x && y && w && h
|
175
|
+
|
176
|
+
sx, sy = sp.w / w, sp.h / h
|
177
|
+
scale sx, sy
|
178
|
+
translate(-x, -y)
|
179
|
+
no_fill
|
180
|
+
stroke_weight 0
|
181
|
+
|
182
|
+
draw_grids
|
183
|
+
draw_selection sx, sy
|
184
|
+
end
|
185
|
+
|
186
|
+
def draw_grids()
|
187
|
+
push do
|
188
|
+
stroke 50, 50, 50
|
189
|
+
shape grid 8
|
190
|
+
stroke 100, 100, 100
|
191
|
+
shape grid 16
|
192
|
+
stroke 150, 150, 150
|
193
|
+
shape grid 32
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
def grid(interval)
|
198
|
+
(@grids ||= {})[interval] ||= create_shape.tap do |sh|
|
199
|
+
w, h = @image.width, @image.height
|
200
|
+
sh.begin_shape LINES
|
201
|
+
(0..w).step(interval).each do |x|
|
202
|
+
sh.vertex x, 0
|
203
|
+
sh.vertex x, h
|
204
|
+
end
|
205
|
+
(0..h).step(interval).each do |y|
|
206
|
+
sh.vertex 0, y
|
207
|
+
sh.vertex w, y
|
208
|
+
end
|
209
|
+
sh.end_shape
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
def draw_selection(scale_x, scale_y)
|
214
|
+
return unless @selection&.size == 4
|
215
|
+
push do
|
216
|
+
stroke 255, 255, 255
|
217
|
+
shader selection_shader.tap {|sh|
|
218
|
+
sh.set :time, frame_count.to_f / 60
|
219
|
+
sh.set :scale, scale_x, scale_y
|
220
|
+
}
|
221
|
+
=begin
|
222
|
+
begin_shape LINES
|
223
|
+
x, y, w, h = @selection
|
224
|
+
vertex x, y, x, 0
|
225
|
+
vertex x + w, y, x + w, 0
|
226
|
+
vertex x + w, y, x, 0
|
227
|
+
vertex x + w, y + h, x + w, 0
|
228
|
+
vertex x + w, y + h, x, 0
|
229
|
+
vertex x, y + h, x + w, 0
|
230
|
+
vertex x, y + h, x, 0
|
231
|
+
vertex x, y, x + w, 0
|
232
|
+
end_shape
|
233
|
+
=end
|
234
|
+
rect(*@selection)
|
235
|
+
end
|
236
|
+
end
|
237
|
+
|
238
|
+
def selection_shader()
|
239
|
+
@selection_shader ||= create_shader nil, <<~END
|
240
|
+
varying vec4 vertTexCoord;
|
241
|
+
uniform float time;
|
242
|
+
uniform vec2 scale;
|
243
|
+
void main()
|
244
|
+
{
|
245
|
+
vec2 pos = vertTexCoord.xy * scale;
|
246
|
+
float t = floor(time * 4.) / 4.;
|
247
|
+
float x = mod( pos.x + time, 4.) < 2. ? 1. : 0.;
|
248
|
+
float y = mod(-pos.y + time, 4.) < 2. ? 1. : 0.;
|
249
|
+
gl_FragColor = x != y ? vec4(0., 0., 0., 1.) : vec4(1., 1., 1., 1.);
|
250
|
+
}
|
251
|
+
END
|
252
|
+
end
|
253
|
+
|
254
|
+
end# Canvas
|
@@ -0,0 +1,92 @@
|
|
1
|
+
using Reight
|
2
|
+
|
3
|
+
|
4
|
+
class Reight::SpriteEditor::Chips
|
5
|
+
|
6
|
+
include Reight::Hookable
|
7
|
+
|
8
|
+
def initialize(app, image, size = 8, &block)
|
9
|
+
hook :frame_changed
|
10
|
+
|
11
|
+
@app, @image = app, image
|
12
|
+
@offset = create_vector
|
13
|
+
|
14
|
+
@app.history.disable do
|
15
|
+
set_frame 0, 0, size, size
|
16
|
+
end
|
17
|
+
|
18
|
+
frame_changed(&block)
|
19
|
+
end
|
20
|
+
|
21
|
+
attr_reader :x, :y, :size
|
22
|
+
|
23
|
+
def set_frame(x, y, w, h)
|
24
|
+
raise 'Chips: width != height' if w != h
|
25
|
+
@x = align_to_grid(x).clamp(0..@image.width)
|
26
|
+
@y = align_to_grid(y).clamp(0..@image.height)
|
27
|
+
@size = w
|
28
|
+
frame_changed! @x, @y, @size, @size
|
29
|
+
end
|
30
|
+
|
31
|
+
def draw()
|
32
|
+
sp = sprite
|
33
|
+
clip sp.x, sp.y, sp.w, sp.h
|
34
|
+
translate(*clamp_offset(@offset).to_a)
|
35
|
+
image @image, 0, 0
|
36
|
+
|
37
|
+
no_fill
|
38
|
+
stroke 255, 255, 255
|
39
|
+
stroke_weight 1
|
40
|
+
rect @x, @y, @size, @size
|
41
|
+
end
|
42
|
+
|
43
|
+
def mouse_pressed(x, y)
|
44
|
+
@prev_pos = create_vector x, y
|
45
|
+
end
|
46
|
+
|
47
|
+
def mouse_released(x, y)
|
48
|
+
@offset = clamp_offset @offset
|
49
|
+
end
|
50
|
+
|
51
|
+
def mouse_dragged(x, y)
|
52
|
+
pos = create_vector x, y
|
53
|
+
@offset += pos - @prev_pos if @prev_pos
|
54
|
+
@prev_pos = pos
|
55
|
+
end
|
56
|
+
|
57
|
+
def mouse_clicked(x, y)
|
58
|
+
set_frame(
|
59
|
+
-@offset.x + align_to_grid(x),
|
60
|
+
-@offset.y + align_to_grid(y),
|
61
|
+
size,
|
62
|
+
size)
|
63
|
+
end
|
64
|
+
|
65
|
+
def sprite()
|
66
|
+
@sprite ||= Sprite.new.tap do |sp|
|
67
|
+
sp.draw {draw}
|
68
|
+
sp.mouse_pressed {mouse_pressed sp.mouse_x, sp.mouse_y}
|
69
|
+
sp.mouse_released {mouse_released sp.mouse_x, sp.mouse_y}
|
70
|
+
sp.mouse_dragged {mouse_dragged sp.mouse_x, sp.mouse_y}
|
71
|
+
sp.mouse_clicked {mouse_clicked sp.mouse_x, sp.mouse_y}
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
private
|
76
|
+
|
77
|
+
def clamp_offset(offset)
|
78
|
+
sp = sprite
|
79
|
+
x = offset.x.clamp([-(@image.width - sp.w), 0].min..0)
|
80
|
+
y = offset.y.clamp([-(@image.height - sp.h), 0].min..0)
|
81
|
+
create_vector align_to_grid(x), align_to_grid(y)
|
82
|
+
end
|
83
|
+
|
84
|
+
def align_to_grid(n)
|
85
|
+
n.to_i / 8 * 8
|
86
|
+
end
|
87
|
+
|
88
|
+
def selected()
|
89
|
+
@selected.call @x, @y, @size, @size
|
90
|
+
end
|
91
|
+
|
92
|
+
end# Chips
|
@@ -0,0 +1,30 @@
|
|
1
|
+
using Reight
|
2
|
+
|
3
|
+
|
4
|
+
class Reight::SpriteEditor::Color < Reight::Button
|
5
|
+
|
6
|
+
def initialize(color, &clicked)
|
7
|
+
super name: '', &clicked
|
8
|
+
@color = color
|
9
|
+
end
|
10
|
+
|
11
|
+
attr_reader :color
|
12
|
+
|
13
|
+
def draw()
|
14
|
+
sp = sprite
|
15
|
+
|
16
|
+
fill(*color)
|
17
|
+
no_stroke
|
18
|
+
rect 0, 0, sp.w, sp.h
|
19
|
+
|
20
|
+
if active?
|
21
|
+
no_fill
|
22
|
+
stroke_weight 1
|
23
|
+
stroke '#000000'
|
24
|
+
rect 2, 2, sp.w - 4, sp.h - 4
|
25
|
+
stroke '#ffffff'
|
26
|
+
rect 1, 1, sp.w - 2, sp.h - 2
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
end# Color
|