pixelflow_canvas 0.7.7 → 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.7"
4
+ VERSION = "0.7.9"
5
5
  end
@@ -47,14 +47,36 @@ 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
 
76
+ def inspect
77
+ "#<Pixelflow::Canvas @ #{@width}x#{@height}>"
78
+ end
79
+
58
80
  attr_reader :width, :height, :color_mode
59
81
 
60
82
  def run(&block)
@@ -123,23 +145,49 @@ module Pixelflow
123
145
  end
124
146
 
125
147
  def flip()
126
- if @draw_mode == :buffered
127
- @socket.write([7].pack('C'))
128
- @socket.write(@screen.pack('C*'))
129
- @socket.flush
130
- 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
131
178
  end
132
179
 
133
180
  def ensure_max_fps(fps)
134
- fps1 = 1.0 / fps
135
- 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)
136
186
  if @last_timestamp
137
- loop do
138
- sleep 0.01
139
- break if (Time.now.to_f - @last_timestamp) >= fps1
140
- end
187
+ remaining = frame_time - (now - @last_timestamp)
188
+ sleep remaining if remaining > 0
141
189
  end
142
- @last_timestamp = Time.now.to_f
190
+ @last_timestamp = Process.clock_gettime(Process::CLOCK_MONOTONIC)
143
191
  end
144
192
 
145
193
  def save_as_png(path)
@@ -250,13 +298,9 @@ module Pixelflow
250
298
  x = x.to_i
251
299
  y = y.to_i
252
300
  return if x < 0 || x >= @width || y < 0 || y >= @height
301
+
253
302
  @x = x
254
303
  @y = y
255
- buffer = [5].pack('C')
256
- buffer += [x].pack((@width <= 256) ? 'C' : 'n')
257
- buffer += [y].pack((@height <= 256) ? 'C' : 'n')
258
- @socket.write(buffer)
259
- @socket.flush
260
304
  end
261
305
 
262
306
  def set_pixel(x, y, r = nil, g = nil, b = nil)
@@ -300,14 +344,8 @@ module Pixelflow
300
344
  offset = @y * @width + @x
301
345
  @screen[offset] = r
302
346
  end
303
- if @draw_mode == :direct
304
- if @color_mode == :rgb
305
- @socket.write([6, r, g, b].pack('CCCC'))
306
- else
307
- @socket.write([6, r].pack('CC'))
308
- end
309
- @socket.flush()
310
- end
347
+ @dirty = true
348
+ present_if_due
311
349
  if @advance_mode == :right
312
350
  @x += 1
313
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.7
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-21 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: []