pixelflow_canvas 0.7.8 → 0.7.9

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.
data/docs/render-docs.rb CHANGED
@@ -11,7 +11,13 @@ palettes = YAML.load(File.read('../lib/pixelflow_canvas/palettes.yaml'))
11
11
  s = StringIO.open do |io|
12
12
  palettes.each do |name, palette|
13
13
  io.puts
14
- io.puts "#### #{name}"
14
+ io.puts "#### #{name.to_s.gsub('_', ' ').capitalize}"
15
+ io.puts
16
+ io.puts <<~END_OF_STRING
17
+ ```ruby
18
+ set_predefined_palette(:#{name})
19
+ ```
20
+ END_OF_STRING
15
21
  io.puts
16
22
  io.puts "<div class='swatches'>"
17
23
  palette.each.with_index do |color, i|
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module PixelflowCanvas
4
- VERSION = "0.7.8"
4
+ VERSION = "0.7.9"
5
5
  end
@@ -47,11 +47,29 @@ module Pixelflow
47
47
  @compose_mode = :copy
48
48
  @palette = VGA_PALETTE.dup
49
49
  @socket = TCPSocket.new('127.0.0.1', 19223)
50
+
51
+
52
+ # Fast transport: all drawing changes the local framebuffer.
53
+ # Complete frames are sent instead of MOVE_TO/SET_PIXEL commands.
54
+ @dirty = false
55
+ @direct_frame_interval = 1.0 / 30.0
56
+ @direct_pixel_counter = 0
57
+ @last_present_timestamp =
58
+ Process.clock_gettime(Process::CLOCK_MONOTONIC)
50
59
  set_size(width, height)
51
60
  set_color_mode(color_mode) if color_mode
52
- @last_timestamp = Time.now.to_f
61
+ @last_timestamp = Process.clock_gettime(Process::CLOCK_MONOTONIC)
62
+ at_exit do
63
+ begin
64
+ present if @dirty && @socket && !@socket.closed?
65
+ rescue IOError, SystemCallError
66
+ # VS Code may already have gone away during shutdown.
67
+ end
68
+ end
69
+
53
70
  if block_given?
54
71
  instance_eval(&block)
72
+ present if @dirty
55
73
  end
56
74
  end
57
75
 
@@ -127,23 +145,49 @@ module Pixelflow
127
145
  end
128
146
 
129
147
  def flip()
130
- if @draw_mode == :buffered
131
- @socket.write([7].pack('C'))
132
- @socket.write(@screen.pack('C*'))
133
- @socket.flush
134
- end
148
+ present
149
+ end
150
+
151
+ # Send one complete framebuffer as one SET_BUFFER packet.
152
+ def present
153
+ return unless @dirty
154
+
155
+ packet = "\x07".b
156
+ packet << @screen.pack('C*')
157
+ @socket.write(packet)
158
+ @socket.flush
159
+
160
+ @dirty = false
161
+ @direct_pixel_counter = 0
162
+ @last_present_timestamp =
163
+ Process.clock_gettime(Process::CLOCK_MONOTONIC)
164
+ end
165
+
166
+ # Direct mode remains progressive without checking the clock for
167
+ # every single pixel. We only test the 30 fps deadline every 1024
168
+ # pixel writes. Existing animation code gets an exact frame boundary
169
+ # through ensure_max_fps below.
170
+ def present_if_due
171
+ return unless @draw_mode == :direct && @dirty
172
+
173
+ @direct_pixel_counter += 1
174
+ return unless (@direct_pixel_counter & 1023).zero?
175
+
176
+ now = Process.clock_gettime(Process::CLOCK_MONOTONIC)
177
+ present if now - @last_present_timestamp >= @direct_frame_interval
135
178
  end
136
179
 
137
180
  def ensure_max_fps(fps)
138
- fps1 = 1.0 / fps
139
- t = Time.now.to_f
181
+ # Existing examples call this once after drawing a frame.
182
+ present if @draw_mode == :direct && @dirty
183
+
184
+ frame_time = 1.0 / fps
185
+ now = Process.clock_gettime(Process::CLOCK_MONOTONIC)
140
186
  if @last_timestamp
141
- loop do
142
- sleep 0.01
143
- break if (Time.now.to_f - @last_timestamp) >= fps1
144
- end
187
+ remaining = frame_time - (now - @last_timestamp)
188
+ sleep remaining if remaining > 0
145
189
  end
146
- @last_timestamp = Time.now.to_f
190
+ @last_timestamp = Process.clock_gettime(Process::CLOCK_MONOTONIC)
147
191
  end
148
192
 
149
193
  def save_as_png(path)
@@ -254,13 +298,9 @@ module Pixelflow
254
298
  x = x.to_i
255
299
  y = y.to_i
256
300
  return if x < 0 || x >= @width || y < 0 || y >= @height
301
+
257
302
  @x = x
258
303
  @y = y
259
- buffer = [5].pack('C')
260
- buffer += [x].pack((@width <= 256) ? 'C' : 'n')
261
- buffer += [y].pack((@height <= 256) ? 'C' : 'n')
262
- @socket.write(buffer)
263
- @socket.flush
264
304
  end
265
305
 
266
306
  def set_pixel(x, y, r = nil, g = nil, b = nil)
@@ -304,14 +344,8 @@ module Pixelflow
304
344
  offset = @y * @width + @x
305
345
  @screen[offset] = r
306
346
  end
307
- if @draw_mode == :direct
308
- if @color_mode == :rgb
309
- @socket.write([6, r, g, b].pack('CCCC'))
310
- else
311
- @socket.write([6, r].pack('CC'))
312
- end
313
- @socket.flush()
314
- end
347
+ @dirty = true
348
+ present_if_due
315
349
  if @advance_mode == :right
316
350
  @x += 1
317
351
  if @x >= @width
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pixelflow_canvas
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.8
4
+ version: 0.7.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - Michael Specht
8
- autorequire:
9
8
  bindir: exe
10
9
  cert_chain: []
11
- date: 2024-11-25 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: chunky_png
@@ -84,7 +83,6 @@ metadata:
84
83
  homepage_uri: https://github.com/specht/pixelflow_canvas_ruby
85
84
  source_code_uri: https://github.com/specht/pixelflow_canvas_ruby
86
85
  changelog_uri: https://github.com/specht/pixelflow_canvas_ruby
87
- post_install_message:
88
86
  rdoc_options: []
89
87
  require_paths:
90
88
  - lib
@@ -99,8 +97,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
99
97
  - !ruby/object:Gem::Version
100
98
  version: '0'
101
99
  requirements: []
102
- rubygems_version: 3.3.15
103
- signing_key:
100
+ rubygems_version: 3.6.7
104
101
  specification_version: 4
105
102
  summary: Ruby driver for the Pixelflow Canvas VS Code extension.
106
103
  test_files: []