pixelflow_canvas 0.4.1 → 0.4.3

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4824696c6996cc136b56dd83a716fa12a273e0682744473b67f0ffb7693b7335
4
- data.tar.gz: 612927ef865f29432b41adbaa11b0d4b6e824a9af15cd75413c7e5c7fa0c84b1
3
+ metadata.gz: 03bac01ad660c83aac3bb58e8b9dc009f07d99d773ebf3e4c9c77106c9016a08
4
+ data.tar.gz: 810c59ec0266aec7f5b4b20b7b411fe5e7c4383db0dd0c1614e0fc1446ae5ffc
5
5
  SHA512:
6
- metadata.gz: ed40b86854a8779791ca67eb41d0b881ea76e917e72305e391f693cdbfaa6157f2e34402038c300f30b1b7d67414c4722ba3808caf5abd50ea76149fe3915016
7
- data.tar.gz: e0311899a97ba6959dc457f1dbb1397c8495a730e99c813e5b5809875e9127344410856d4bfc3e2afed6b504492693aeffedf62b4f1937702edc6a49f4d11af7
6
+ metadata.gz: 1f4d69987a229d3c369acaab172efb8d39a189ed739b0e21f5078de233b612eff4b8daaf9d85eea46a8b9c5020aafdc528fd3e6cca2f5618ca3d87e5328f1b41
7
+ data.tar.gz: 921f5a582cd70c7024e502feae11dbd2eed01eb59fa6487bc9534913b859125d8d0fe6a13665bf389184137a6f9f2b563be266832002e5fa88c772b5e5476b6f
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module PixelflowCanvas
4
- VERSION = "0.4.1"
4
+ VERSION = "0.4.3"
5
5
  end
@@ -0,0 +1,50 @@
1
+ VGA_PALETTE = [
2
+ 0x00,0x00,0x00,0x00,0x00,0xaa,0x00,0xaa,0x00,0x00,0xaa,0xaa,0xaa,0x00,0x00,0xaa,
3
+ 0x00,0xaa,0xaa,0x55,0x00,0xaa,0xaa,0xaa,0x55,0x55,0x55,0x55,0x55,0xff,0x55,0xff,
4
+ 0x55,0x55,0xff,0xff,0xff,0x55,0x55,0xff,0x55,0xff,0xff,0xff,0x55,0xff,0xff,0xff,
5
+ 0x00,0x00,0x00,0x14,0x14,0x14,0x20,0x20,0x20,0x2c,0x2c,0x2c,0x38,0x38,0x38,0x45,
6
+ 0x45,0x45,0x51,0x51,0x51,0x61,0x61,0x61,0x71,0x71,0x71,0x82,0x82,0x82,0x92,0x92,
7
+ 0x92,0xa2,0xa2,0xa2,0xb6,0xb6,0xb6,0xcb,0xcb,0xcb,0xe3,0xe3,0xe3,0xff,0xff,0xff,
8
+ 0x00,0x00,0xff,0x41,0x00,0xff,0x7d,0x00,0xff,0xbe,0x00,0xff,0xff,0x00,0xff,0xff,
9
+ 0x00,0xbe,0xff,0x00,0x7d,0xff,0x00,0x41,0xff,0x00,0x00,0xff,0x41,0x00,0xff,0x7d,
10
+ 0x00,0xff,0xbe,0x00,0xff,0xff,0x00,0xbe,0xff,0x00,0x7d,0xff,0x00,0x41,0xff,0x00,
11
+ 0x00,0xff,0x00,0x00,0xff,0x41,0x00,0xff,0x7d,0x00,0xff,0xbe,0x00,0xff,0xff,0x00,
12
+ 0xbe,0xff,0x00,0x7d,0xff,0x00,0x41,0xff,0x7d,0x7d,0xff,0x9e,0x7d,0xff,0xbe,0x7d,
13
+ 0xff,0xdf,0x7d,0xff,0xff,0x7d,0xff,0xff,0x7d,0xdf,0xff,0x7d,0xbe,0xff,0x7d,0x9e,
14
+ 0xff,0x7d,0x7d,0xff,0x9e,0x7d,0xff,0xbe,0x7d,0xff,0xdf,0x7d,0xff,0xff,0x7d,0xdf,
15
+ 0xff,0x7d,0xbe,0xff,0x7d,0x9e,0xff,0x7d,0x7d,0xff,0x7d,0x7d,0xff,0x9e,0x7d,0xff,
16
+ 0xbe,0x7d,0xff,0xdf,0x7d,0xff,0xff,0x7d,0xdf,0xff,0x7d,0xbe,0xff,0x7d,0x9e,0xff,
17
+ 0xb6,0xb6,0xff,0xc7,0xb6,0xff,0xdb,0xb6,0xff,0xeb,0xb6,0xff,0xff,0xb6,0xff,0xff,
18
+ 0xb6,0xeb,0xff,0xb6,0xdb,0xff,0xb6,0xc7,0xff,0xb6,0xb6,0xff,0xc7,0xb6,0xff,0xdb,
19
+ 0xb6,0xff,0xeb,0xb6,0xff,0xff,0xb6,0xeb,0xff,0xb6,0xdb,0xff,0xb6,0xc7,0xff,0xb6,
20
+ 0xb6,0xff,0xb6,0xb6,0xff,0xc7,0xb6,0xff,0xdb,0xb6,0xff,0xeb,0xb6,0xff,0xff,0xb6,
21
+ 0xeb,0xff,0xb6,0xdb,0xff,0xb6,0xc7,0xff,0x00,0x00,0x71,0x1c,0x00,0x71,0x38,0x00,
22
+ 0x71,0x55,0x00,0x71,0x71,0x00,0x71,0x71,0x00,0x55,0x71,0x00,0x38,0x71,0x00,0x1c,
23
+ 0x71,0x00,0x00,0x71,0x1c,0x00,0x71,0x38,0x00,0x71,0x55,0x00,0x71,0x71,0x00,0x55,
24
+ 0x71,0x00,0x38,0x71,0x00,0x1c,0x71,0x00,0x00,0x71,0x00,0x00,0x71,0x1c,0x00,0x71,
25
+ 0x38,0x00,0x71,0x55,0x00,0x71,0x71,0x00,0x55,0x71,0x00,0x38,0x71,0x00,0x1c,0x71,
26
+ 0x38,0x38,0x71,0x45,0x38,0x71,0x55,0x38,0x71,0x61,0x38,0x71,0x71,0x38,0x71,0x71,
27
+ 0x38,0x61,0x71,0x38,0x55,0x71,0x38,0x45,0x71,0x38,0x38,0x71,0x45,0x38,0x71,0x55,
28
+ 0x38,0x71,0x61,0x38,0x71,0x71,0x38,0x61,0x71,0x38,0x55,0x71,0x38,0x45,0x71,0x38,
29
+ 0x38,0x71,0x38,0x38,0x71,0x45,0x38,0x71,0x55,0x38,0x71,0x61,0x38,0x71,0x71,0x38,
30
+ 0x61,0x71,0x38,0x55,0x71,0x38,0x45,0x71,0x51,0x51,0x71,0x59,0x51,0x71,0x61,0x51,
31
+ 0x71,0x69,0x51,0x71,0x71,0x51,0x71,0x71,0x51,0x69,0x71,0x51,0x61,0x71,0x51,0x59,
32
+ 0x71,0x51,0x51,0x71,0x59,0x51,0x71,0x61,0x51,0x71,0x69,0x51,0x71,0x71,0x51,0x69,
33
+ 0x71,0x51,0x61,0x71,0x51,0x59,0x71,0x51,0x51,0x71,0x51,0x51,0x71,0x59,0x51,0x71,
34
+ 0x61,0x51,0x71,0x69,0x51,0x71,0x71,0x51,0x69,0x71,0x51,0x61,0x71,0x51,0x59,0x71,
35
+ 0x00,0x00,0x41,0x10,0x00,0x41,0x20,0x00,0x41,0x30,0x00,0x41,0x41,0x00,0x41,0x41,
36
+ 0x00,0x30,0x41,0x00,0x20,0x41,0x00,0x10,0x41,0x00,0x00,0x41,0x10,0x00,0x41,0x20,
37
+ 0x00,0x41,0x30,0x00,0x41,0x41,0x00,0x30,0x41,0x00,0x20,0x41,0x00,0x10,0x41,0x00,
38
+ 0x00,0x41,0x00,0x00,0x41,0x10,0x00,0x41,0x20,0x00,0x41,0x30,0x00,0x41,0x41,0x00,
39
+ 0x30,0x41,0x00,0x20,0x41,0x00,0x10,0x41,0x20,0x20,0x41,0x28,0x20,0x41,0x30,0x20,
40
+ 0x41,0x38,0x20,0x41,0x41,0x20,0x41,0x41,0x20,0x38,0x41,0x20,0x30,0x41,0x20,0x28,
41
+ 0x41,0x20,0x20,0x41,0x28,0x20,0x41,0x30,0x20,0x41,0x38,0x20,0x41,0x41,0x20,0x38,
42
+ 0x41,0x20,0x30,0x41,0x20,0x28,0x41,0x20,0x20,0x41,0x20,0x20,0x41,0x28,0x20,0x41,
43
+ 0x30,0x20,0x41,0x38,0x20,0x41,0x41,0x20,0x38,0x41,0x20,0x30,0x41,0x20,0x28,0x41,
44
+ 0x2c,0x2c,0x41,0x30,0x2c,0x41,0x34,0x2c,0x41,0x3c,0x2c,0x41,0x41,0x2c,0x41,0x41,
45
+ 0x2c,0x3c,0x41,0x2c,0x34,0x41,0x2c,0x30,0x41,0x2c,0x2c,0x41,0x30,0x2c,0x41,0x34,
46
+ 0x2c,0x41,0x3c,0x2c,0x41,0x41,0x2c,0x3c,0x41,0x2c,0x34,0x41,0x2c,0x30,0x41,0x2c,
47
+ 0x2c,0x41,0x2c,0x2c,0x41,0x30,0x2c,0x41,0x34,0x2c,0x41,0x3c,0x2c,0x41,0x41,0x2c,
48
+ 0x3c,0x41,0x2c,0x34,0x41,0x2c,0x30,0x41,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
49
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
50
+ ]
@@ -1,6 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative "pixelflow_canvas/version"
4
+ require_relative "pixelflow_canvas/vga_palette.rb"
5
+ require 'chunky_png'
4
6
  require 'socket'
5
7
  require 'time'
6
8
 
@@ -18,36 +20,35 @@ module Pixelflow
18
20
  :direct => 0,
19
21
  :buffered => 1
20
22
  }
23
+ COMPOSE_MODES = {
24
+ :over => 0,
25
+ :add => 1,
26
+ :subtract => 2
27
+ }
28
+ INTERPOLATION_MODES = {
29
+ :nearest => 0,
30
+ :bilinear => 1,
31
+ }
21
32
  def initialize(width, height, color_mode = nil)
22
33
  @width = 320
23
34
  @height = 180
24
35
  @x = 0
25
36
  @y = 0
37
+ @r = color_mode == :palette ? 15 : 255
38
+ @g = color_mode == :palette ? 0 : 255
39
+ @b = color_mode == :palette ? 0 : 255
26
40
  @color_mode = :rgb
27
41
  @advance_mode = :right
28
42
  @draw_mode = :direct
29
- @palette = [0] * 768
43
+ @compose_mode = :over
44
+ @palette = VGA_PALETTE.dup
30
45
  @socket = TCPSocket.new('127.0.0.1', 19223)
31
46
  set_size(width, height)
32
47
  set_color_mode(color_mode) if color_mode
33
48
  @last_timestamp = Time.now.to_f
34
49
  end
35
50
 
36
- def run(&block)
37
- yield(self)
38
- end
39
-
40
- def recreate_screen()
41
- @screen = [0] * @width * @height * (@color_mode == :rgb ? 3 : 1)
42
- end
43
-
44
- def set_draw_mode(mode)
45
- unless DRAW_MODES.keys.include?(mode)
46
- raise "Invalid draw mode: #{mode}"
47
- end
48
- @draw_mode = mode
49
- recreate_screen()
50
- end
51
+ attr_reader :width, :height
51
52
 
52
53
  def set_size(width, height)
53
54
  @x = 0
@@ -59,25 +60,24 @@ module Pixelflow
59
60
  @socket.flush
60
61
  end
61
62
 
63
+ def recreate_screen()
64
+ @screen = [0] * @width * @height * (@color_mode == :rgb ? 3 : 1)
65
+ end
66
+
62
67
  def set_color_mode(mode)
63
68
  unless COLOR_MODES.keys.include?(mode)
64
69
  raise "Invalid color mode: #{mode}"
65
70
  end
66
71
  @color_mode = mode
72
+ if mode == :palette
73
+ @palette = VGA_PALETTE.dup
74
+ end
67
75
  recreate_screen()
68
76
  @socket.write([2, COLOR_MODES[@color_mode]].pack('CC'))
69
77
  @socket.flush
70
78
  end
71
79
 
72
- def set_palette(i, r, g, b)
73
- i = i % 256
74
- r = (r % 256) << 2
75
- g = (g % 256) << 2
76
- b = (b % 256) << 2
77
- @socket.write([3, i, r, g, b].pack('CCCCC'))
78
- end
79
-
80
- def set_advance(mode)
80
+ def set_advance_mode(mode)
81
81
  unless ADVANCE_MODES.keys.include?(mode)
82
82
  raise "Invalid advance mode: #{mode}"
83
83
  end
@@ -86,11 +86,91 @@ module Pixelflow
86
86
  @socket.flush
87
87
  end
88
88
 
89
+ def set_draw_mode(mode)
90
+ unless DRAW_MODES.keys.include?(mode)
91
+ raise "Invalid draw mode: #{mode}"
92
+ end
93
+ @draw_mode = mode
94
+ end
95
+
96
+ def set_compose_mode(mode)
97
+ unless COMPOSE_MODES.keys.include?(mode)
98
+ raise "Invalid compose mode: #{mode}"
99
+ end
100
+ if mode != :over && @color_mode != :rgb
101
+ raise "Cannot switch compose mode to #{mode} in palette color mode!"
102
+ end
103
+ @compose_mode = mode
104
+ end
105
+
106
+ def set_interpolation_mode(mode)
107
+ unless INTERPOLATION_MODES.keys.include?(mode)
108
+ raise "Invalid interpolation mode: #{mode}"
109
+ end
110
+ @socket.write([8, INTERPOLATION_MODES[mode]].pack('CC'))
111
+ @socket.flush
112
+ end
113
+
114
+ def flip()
115
+ if @draw_mode == :buffered
116
+ @socket.write([7].pack('C'))
117
+ @socket.write(@screen.pack('C*'))
118
+ @socket.flush
119
+ end
120
+ end
121
+
122
+ def ensure_max_fps(fps)
123
+ fps1 = 1.0 / fps
124
+ t = Time.now.to_f
125
+ dt = t - @last_timestamp
126
+ sleep(fps1 - dt) if dt < fps1
127
+ @last_timestamp = t
128
+ end
129
+
130
+ def save_as_png(path)
131
+ if @color_mode == :rgb
132
+ image = ChunkyPNG::Image.from_rgb_stream(@width, @height, @screen.pack('C*'))
133
+ image.save(path)
134
+ else
135
+ buffer = [0] * @width * @height * 3
136
+ offset = 0
137
+ source = 0
138
+ (0...@height).each do |y|
139
+ (0...@width).each do |x|
140
+ i = @screen[source]
141
+ buffer[offset + 0] = @palette[i + 0]
142
+ buffer[offset + 1] = @palette[i + 1]
143
+ buffer[offset + 2] = @palette[i + 2]
144
+ source += 1
145
+ offset += 3
146
+ end
147
+ end
148
+ image = ChunkyPNG::Image.from_rgb_stream(@width, @height, buffer.pack('C*'))
149
+ image.save(path)
150
+ end
151
+ end
152
+
153
+ def set_color(r, g = 0, b = 0)
154
+ @r = r
155
+ @g = g
156
+ @b = b
157
+ end
158
+
159
+ def set_palette(i, r, g, b)
160
+ i = i.to_i.clamp(0, 255)
161
+ r = r.to_i.clamp(0, 255)
162
+ g = g.to_i.clamp(0, 255)
163
+ b = b.to_i.clamp(0, 255)
164
+ @palette[i * 3 + 0] = r
165
+ @palette[i * 3 + 1] = g
166
+ @palette[i * 3 + 2] = b
167
+ @socket.write([3, i, r, g, b].pack('CCCCC'))
168
+ @socket.flush
169
+ end
170
+
89
171
  def move_to(x, y)
90
- x0 = x0.to_i
91
- y0 = y0.to_i
92
- x1 = x1.to_i
93
- y1 = y1.to_i
172
+ x = x.to_i
173
+ y = y.to_i
94
174
  return if x < 0 || x >= @width || y < 0 || y >= @height
95
175
  @x = x
96
176
  @y = y
@@ -101,7 +181,10 @@ module Pixelflow
101
181
  @socket.flush
102
182
  end
103
183
 
104
- def set_pixel(x, y, r, g = 0, b = 0)
184
+ def set_pixel(x, y, r = nil, g = nil, b = nil)
185
+ r ||= @r
186
+ g ||= @g
187
+ b ||= @b
105
188
  x0 = x0.to_i
106
189
  y0 = y0.to_i
107
190
  x1 = x1.to_i
@@ -112,6 +195,14 @@ module Pixelflow
112
195
  end
113
196
  if @color_mode == :rgb
114
197
  offset = (@y * @width + @x) * 3
198
+ if @compose_mode == :add
199
+ r += @screen[offset + 0]
200
+ g += @screen[offset + 1]
201
+ b += @screen[offset + 2]
202
+ r = 255 if r > 255
203
+ g = 255 if g > 255
204
+ b = 255 if b > 255
205
+ end
115
206
  @screen[offset + 0] = r
116
207
  @screen[offset + 1] = g
117
208
  @screen[offset + 2] = b
@@ -155,52 +246,36 @@ module Pixelflow
155
246
  end
156
247
  end
157
248
 
158
- def flip()
159
- if @draw_mode == :buffered
160
- @socket.write([7].pack('C'))
161
- @socket.write(@screen.pack('C*'))
162
- @socket.flush
163
- end
164
- end
165
-
166
- def ensure_max_fps(fps)
167
- fps1 = 1.0 / fps
168
- t = Time.now.to_f
169
- dt = t - @last_timestamp
170
- sleep(fps1 - dt) if dt < fps1
171
- @last_timestamp = t
172
- end
173
-
174
- def draw_rect(x0, y0, x1, y1, color)
249
+ def draw_rect(x0, y0, x1, y1)
175
250
  x0 = x0.to_i
176
251
  y0 = y0.to_i
177
252
  x1 = x1.to_i
178
253
  y1 = y1.to_i
179
254
  (x0..x1).each do |x|
180
- set_pixel(x, y0, color)
255
+ set_pixel(x, y0)
181
256
  end
182
257
  (x0..x1).each do |x|
183
- set_pixel(x, y1, color)
258
+ set_pixel(x, y1)
184
259
  end
185
260
  (y0+1..y1-1).each do |y|
186
- set_pixel(x0, y, color)
187
- set_pixel(x1, y, color)
261
+ set_pixel(x0, y)
262
+ set_pixel(x1, y)
188
263
  end
189
264
  end
190
265
 
191
- def fill_rect(x0, y0, x1, y1, color)
266
+ def fill_rect(x0, y0, x1, y1)
192
267
  x0 = x0.to_i
193
268
  y0 = y0.to_i
194
269
  x1 = x1.to_i
195
270
  y1 = y1.to_i
196
271
  (y0..y1).each do |y|
197
272
  (x0..x1).each do |x|
198
- set_pixel(x, y, color)
273
+ set_pixel(x, y)
199
274
  end
200
275
  end
201
276
  end
202
277
 
203
- def draw_line(x0, y0, x1, y1, color)
278
+ def draw_line(x0, y0, x1, y1)
204
279
  x0 = x0.to_i
205
280
  y0 = y0.to_i
206
281
  x1 = x1.to_i
@@ -211,7 +286,7 @@ module Pixelflow
211
286
  sy = y0 < y1 ? 1 : -1
212
287
  err = dx - dy
213
288
  loop do
214
- set_pixel(x0, y0, color)
289
+ set_pixel(x0, y0)
215
290
  break if x0 == x1 && y0 == y1
216
291
  e2 = 2 * err
217
292
  if e2 > -dy
@@ -225,19 +300,19 @@ module Pixelflow
225
300
  end
226
301
  end
227
302
 
228
- def draw_circle(x, y, radius, color)
303
+ def draw_circle(x, y, r)
229
304
  x = x.to_i
230
305
  y = y.to_i
231
- radius = radius.to_i
232
- f = 1 - radius
306
+ r = r.to_i
307
+ f = 1 - r
233
308
  ddF_x = 1
234
- ddF_y = -2 * radius
309
+ ddF_y = -2 * r
235
310
  xx = 0
236
- yy = radius
237
- set_pixel(x, y + radius, color)
238
- set_pixel(x, y - radius, color)
239
- set_pixel(x + radius, y, color)
240
- set_pixel(x - radius, y, color)
311
+ yy = r
312
+ set_pixel(x, y + r)
313
+ set_pixel(x, y - r)
314
+ set_pixel(x + r, y)
315
+ set_pixel(x - r, y)
241
316
  while xx < yy
242
317
  if f >= 0
243
318
  yy -= 1
@@ -247,18 +322,18 @@ module Pixelflow
247
322
  xx += 1
248
323
  ddF_x += 2
249
324
  f += ddF_x
250
- set_pixel(x + xx, y + yy, color)
251
- set_pixel(x - xx, y + yy, color)
252
- set_pixel(x + xx, y - yy, color)
253
- set_pixel(x - xx, y - yy, color)
254
- set_pixel(x + yy, y + xx, color)
255
- set_pixel(x - yy, y + xx, color)
256
- set_pixel(x + yy, y - xx, color)
257
- set_pixel(x - yy, y - xx, color)
325
+ set_pixel(x + xx, y + yy)
326
+ set_pixel(x - xx, y + yy)
327
+ set_pixel(x + xx, y - yy)
328
+ set_pixel(x - xx, y - yy)
329
+ set_pixel(x + yy, y + xx)
330
+ set_pixel(x - yy, y + xx)
331
+ set_pixel(x + yy, y - xx)
332
+ set_pixel(x - yy, y - xx)
258
333
  end
259
334
  end
260
335
 
261
- def fill_circle(x, y, r, color)
336
+ def fill_circle(x, y, r)
262
337
  x = x.to_i
263
338
  y = y.to_i
264
339
  r = r.to_i
@@ -268,7 +343,7 @@ module Pixelflow
268
343
  xx = 0
269
344
  yy = r
270
345
  (y - r..y + r).each do |i|
271
- set_pixel(x, i, color)
346
+ set_pixel(x, i)
272
347
  end
273
348
  while xx < yy
274
349
  if f >= 0
@@ -280,33 +355,33 @@ module Pixelflow
280
355
  ddF_x += 2
281
356
  f += ddF_x
282
357
  (y - yy..y + yy).each do |i|
283
- set_pixel(x + xx, i, color)
284
- set_pixel(x - xx, i, color)
358
+ set_pixel(x + xx, i)
359
+ set_pixel(x - xx, i)
285
360
  end
286
361
  (y - xx..y + xx).each do |i|
287
- set_pixel(x + yy, i, color)
288
- set_pixel(x - yy, i, color)
362
+ set_pixel(x + yy, i)
363
+ set_pixel(x - yy, i)
289
364
  end
290
365
  end
291
366
  end
292
367
 
293
- def draw_ellipse(x, y, a, b, color)
368
+ def draw_ellipse(x, y, ra, rb)
294
369
  x = x.to_i
295
370
  y = y.to_i
296
- a = a.to_i
297
- b = b.to_i
298
- a2 = a * a
299
- b2 = b * b
371
+ ra = ra.to_i
372
+ rb = rb.to_i
373
+ a2 = ra * ra
374
+ b2 = rb * rb
300
375
  fa2 = 4 * a2
301
376
  fb2 = 4 * b2
302
377
  x0 = 0
303
378
  y0 = b
304
- sigma = 2 * b2 + a2 * (1 - 2 * b)
379
+ sigma = 2 * b2 + a2 * (1 - 2 * rb)
305
380
  while b2 * x0 <= a2 * y0
306
- set_pixel(x + x0, y + y0, color)
307
- set_pixel(x - x0, y + y0, color)
308
- set_pixel(x + x0, y - y0, color)
309
- set_pixel(x - x0, y - y0, color)
381
+ set_pixel(x + x0, y + y0)
382
+ set_pixel(x - x0, y + y0)
383
+ set_pixel(x + x0, y - y0)
384
+ set_pixel(x - x0, y - y0)
310
385
  if sigma >= 0
311
386
  sigma += fa2 * (1 - y0)
312
387
  y0 -= 1
@@ -316,12 +391,12 @@ module Pixelflow
316
391
  end
317
392
  x0 = a
318
393
  y0 = 0
319
- sigma = 2 * a2 + b2 * (1 - 2 * a)
394
+ sigma = 2 * a2 + b2 * (1 - 2 * ra)
320
395
  while a2 * y0 <= b2 * x0
321
- set_pixel(x + x0, y + y0, color)
322
- set_pixel(x - x0, y + y0, color)
323
- set_pixel(x + x0, y - y0, color)
324
- set_pixel(x - x0, y - y0, color)
396
+ set_pixel(x + x0, y + y0)
397
+ set_pixel(x - x0, y + y0)
398
+ set_pixel(x + x0, y - y0)
399
+ set_pixel(x - x0, y - y0)
325
400
  if sigma >= 0
326
401
  sigma += fb2 * (1 - x0)
327
402
  x0 -= 1
@@ -331,22 +406,22 @@ module Pixelflow
331
406
  end
332
407
  end
333
408
 
334
- def fill_ellipse(x, y, a, b, color)
409
+ def fill_ellipse(x, y, ra, rb)
335
410
  x = x.to_i
336
411
  y = y.to_i
337
- a = a.to_i
338
- b = b.to_i
339
- a2 = a * a
340
- b2 = b * b
412
+ ra = ra.to_i
413
+ rb = rb.to_i
414
+ a2 = ra * ra
415
+ b2 = rb * rb
341
416
  fa2 = 4 * a2
342
417
  fb2 = 4 * b2
343
418
  x0 = 0
344
419
  y0 = b
345
- sigma = 2 * b2 + a2 * (1 - 2 * b)
420
+ sigma = 2 * b2 + a2 * (1 - 2 * rb)
346
421
  while b2 * x0 <= a2 * y0
347
422
  (x - x0..x + x0).each do |i|
348
- set_pixel(i, y + y0, color)
349
- set_pixel(i, y - y0, color)
423
+ set_pixel(i, y + y0)
424
+ set_pixel(i, y - y0)
350
425
  end
351
426
  if sigma >= 0
352
427
  sigma += fa2 * (1 - y0)
@@ -357,11 +432,11 @@ module Pixelflow
357
432
  end
358
433
  x0 = a
359
434
  y0 = 0
360
- sigma = 2 * a2 + b2 * (1 - 2 * a)
435
+ sigma = 2 * a2 + b2 * (1 - 2 * ra)
361
436
  while a2 * y0 <= b2 * x0
362
437
  (x - x0..x + x0).each do |i|
363
- set_pixel(i, y + y0, color)
364
- set_pixel(i, y - y0, color)
438
+ set_pixel(i, y + y0)
439
+ set_pixel(i, y - y0)
365
440
  end
366
441
  if sigma >= 0
367
442
  sigma += fb2 * (1 - x0)
@@ -372,7 +447,7 @@ module Pixelflow
372
447
  end
373
448
  end
374
449
 
375
- def draw_quadratic_bezier(x0, y0, x1, y1, x2, y2, color, steps = 100)
450
+ def draw_quadratic_bezier(x0, y0, x1, y1, x2, y2, steps = 100)
376
451
  steps = steps.to_i
377
452
  xp = nil
378
453
  yp = nil
@@ -381,14 +456,14 @@ module Pixelflow
381
456
  x = (1 - t) ** 2 * x0 + 2 * (1 - t) * t * x1 + t ** 2 * x2
382
457
  y = (1 - t) ** 2 * y0 + 2 * (1 - t) * t * y1 + t ** 2 * y2
383
458
  if xp && yp
384
- draw_line(xp.to_i, yp.to_i, x.to_i, y.to_i, color)
459
+ draw_line(xp.to_i, yp.to_i, x.to_i, y.to_i)
385
460
  end
386
461
  xp = x
387
462
  yp = y
388
463
  end
389
464
  end
390
465
 
391
- def draw_cubic_bezier(x0, y0, x1, y1, x2, y2, x3, y3, color, steps = 100)
466
+ def draw_cubic_bezier(x0, y0, x1, y1, x2, y2, x3, y3, steps = 100)
392
467
  steps = steps.to_i
393
468
  xp = nil
394
469
  yp = nil
@@ -397,17 +472,49 @@ module Pixelflow
397
472
  x = (1 - t) ** 3 * x0 + 3 * (1 - t) ** 2 * t * x1 + 3 * (1 - t) * t ** 2 * x2 + t ** 3 * x3
398
473
  y = (1 - t) ** 3 * y0 + 3 * (1 - t) ** 2 * t * y1 + 3 * (1 - t) * t ** 2 * y2 + t ** 3 * y3
399
474
  if xp && yp
400
- draw_line(xp.to_i, yp.to_i, x.to_i, y.to_i, color)
475
+ draw_line(xp.to_i, yp.to_i, x.to_i, y.to_i)
401
476
  end
402
477
  xp = x
403
478
  yp = y
404
479
  end
405
480
  end
406
481
 
407
- def draw_triangle(x0, y0, x1, y1, x2, y2, color)
408
- draw_line(x0, y0, x1, y1, color)
409
- draw_line(x1, y1, x2, y2, color)
410
- draw_line(x2, y2, x0, y0, color)
482
+ def draw_triangle(x0, y0, x1, y1, x2, y2)
483
+ draw_line(x0, y0, x1, y1)
484
+ draw_line(x1, y1, x2, y2)
485
+ draw_line(x2, y2, x0, y0)
486
+ end
487
+ end
488
+
489
+ class Turtle
490
+ def initialize(canvas)
491
+ @canvas = canvas
492
+ @x = canvas.width / 2.0
493
+ @y = canvas.height / 2.0
494
+ @phi = 270.0
495
+ @pen_down = true
496
+ end
497
+
498
+ attr_accessor :x, :y, :phi, :color, :pen_down
499
+
500
+ def forward(l)
501
+ nx = @x + Math.cos(@phi * Math::PI / 180.0) * l
502
+ ny = @y + Math.sin(@phi * Math::PI / 180.0) * l
503
+ @canvas.draw_line(@x, @y, nx, ny) if @pen_down
504
+ @x = nx
505
+ @y = ny
506
+ end
507
+
508
+ def set_color(r = 0, g = nil, b = nil)
509
+ @canvas.set_color(r, g, b)
510
+ end
511
+
512
+ def turn_left(phi)
513
+ @phi -= phi
514
+ end
515
+
516
+ def turn_right(phi)
517
+ @phi += phi
411
518
  end
412
519
  end
413
520
  end
data/test-anaglyph.rb ADDED
@@ -0,0 +1,15 @@
1
+ require './lib/pixelflow_canvas.rb'
2
+
3
+ width = 256
4
+ height = 256
5
+
6
+ canvas = Pixelflow::Canvas.new(width, height, :rgb)
7
+ canvas.set_compose_mode(:add)
8
+
9
+ canvas.set_color(255, 0, 0)
10
+ canvas.draw_line(10, 10, 100, 200)
11
+
12
+ canvas.set_color(0, 255, 0)
13
+ canvas.draw_line(20, 10, 90, 200)
14
+
15
+ canvas.save_as_png('anaglyph.png')
data/test-draw.rb ADDED
@@ -0,0 +1,26 @@
1
+ require './lib/pixelflow_canvas.rb'
2
+
3
+ width = 256
4
+ height = 256
5
+
6
+ canvas = Pixelflow::Canvas.new(width, height, :palette)
7
+ canvas.set_interpolation_mode(:bilinear)
8
+ turtle = Pixelflow::Turtle.new(canvas)
9
+ turtle.set_color(13)
10
+
11
+ def draw(canvas, x0, y0, x1, y1, x2, y2, level)
12
+ canvas.draw_triangle(x0, y0, x1, y1, x2, y2)
13
+ mx0 = (x0 + x1) / 2
14
+ my0 = (y0 + y1) / 2
15
+ mx1 = (x1 + x2) / 2
16
+ my1 = (y1 + y2) / 2
17
+ mx2 = (x2 + x0) / 2
18
+ my2 = (y2 + y0) / 2
19
+ if level > 0
20
+ draw(canvas, x0, y0, mx0, my0, mx2, my2, level - 1)
21
+ draw(canvas, x1, y1, mx1, my1, mx0, my0, level - 1)
22
+ draw(canvas, x2, y2, mx2, my2, mx1, my1, level - 1)
23
+ end
24
+ end
25
+
26
+ draw(canvas, 128, 10, 10, 186, 246, 246, 5)
data/test-sirds.rb ADDED
@@ -0,0 +1,37 @@
1
+ require './lib/pixelflow_canvas.rb'
2
+
3
+ def depth(x, y)
4
+ r = (x - 128) ** 2 + (y - 128) ** 2
5
+ return 10 if r < 5000
6
+ r * 0.001
7
+ end
8
+
9
+ width = 256
10
+ height = 256
11
+
12
+ canvas = Pixelflow::Canvas.new(width, height, :palette)
13
+ (0...64).each { |i| canvas.set_palette(i, i * 4, i * 4, i * 4) }
14
+ (0...height).each do |y|
15
+ (0...48).each do |x|
16
+ canvas.set_pixel(x, y, rand(64))
17
+ end
18
+ end
19
+ (0...height).each do |y|
20
+ sx = 0
21
+ dx = 48
22
+ while dx < width
23
+ c = canvas.get_pixel(sx, y)
24
+ canvas.set_pixel(dx, y, c)
25
+ dx += 1
26
+ sx = dx - 48 + depth(dx - 24, y)
27
+ end
28
+ end
29
+
30
+ # (0...height).each do |y|
31
+ # (0...width).each do |x|
32
+ # d = depth(x, y)
33
+ # canvas.set_pixel(x, y, d)
34
+ # end
35
+ # end
36
+
37
+ canvas.save_as_png('sirds.png')
data/test-turtle.rb ADDED
@@ -0,0 +1,14 @@
1
+ require './lib/pixelflow_canvas.rb'
2
+
3
+ width = 256
4
+ height = 256
5
+
6
+ canvas = Pixelflow::Canvas.new(width, height, :palette)
7
+ turtle = Pixelflow::Turtle.new(canvas)
8
+ turtle.set_color(13)
9
+
10
+ turtle.forward(10)
11
+ turtle.turn_right(90)
12
+ turtle.forward(10)
13
+ turtle.turn_right(90)
14
+ turtle.forward(10)
data/test.rb ADDED
@@ -0,0 +1,36 @@
1
+ require './lib/pixelflow_canvas.rb'
2
+
3
+ def depth(x, y)
4
+ r = (x - 128) ** 2 + (y - 128) ** 2
5
+ return 10 if r < 5000
6
+ r * 0.001
7
+ end
8
+
9
+ width = 256
10
+ height = 256
11
+
12
+ canvas = Pixelflow::Canvas.new(width, height, :palette)
13
+ (0...64).each { |i| canvas.set_palette(i, i, i, i) }
14
+ (0...height).each do |y|
15
+ (0...48).each do |x|
16
+ canvas.set_pixel(x, y, rand(64))
17
+ end
18
+ end
19
+ (0...height).each do |y|
20
+ sx = 0
21
+ dx = 48
22
+ while dx < width
23
+ c = canvas.get_pixel(sx, y)
24
+ canvas.set_pixel(dx, y, c)
25
+ dx += 1
26
+ sx = dx - 48 + depth(dx - 24, y)
27
+ end
28
+ end
29
+
30
+ # (0...height).each do |y|
31
+ # (0...width).each do |x|
32
+ # d = depth(x, y)
33
+ # canvas.set_pixel(x, y, d)
34
+ # end
35
+ # end
36
+
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pixelflow_canvas
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.1
4
+ version: 0.4.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Michael Specht
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-10-24 00:00:00.000000000 Z
12
- dependencies: []
11
+ date: 2024-10-28 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: chunky_png
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 1.4.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 1.4.0
13
27
  description: Use a virtual CRT for old school graphics programming, in VS Code, from
14
28
  Ruby.
15
29
  email:
@@ -23,7 +37,13 @@ files:
23
37
  - Rakefile
24
38
  - lib/pixelflow_canvas.rb
25
39
  - lib/pixelflow_canvas/version.rb
40
+ - lib/pixelflow_canvas/vga_palette.rb
26
41
  - sig/pixelflow_canvas.rbs
42
+ - test-anaglyph.rb
43
+ - test-draw.rb
44
+ - test-sirds.rb
45
+ - test-turtle.rb
46
+ - test.rb
27
47
  homepage: https://github.com/specht/pixelflow_canvas_ruby
28
48
  licenses:
29
49
  - GPL-3.0-only