pixelflow_canvas 0.4.2 → 0.5.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.
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module PixelflowCanvas
4
- VERSION = "0.4.2"
4
+ VERSION = "0.5.0"
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
 
@@ -39,7 +41,7 @@ module Pixelflow
39
41
  @advance_mode = :right
40
42
  @draw_mode = :direct
41
43
  @compose_mode = :over
42
- @palette = [0] * 768
44
+ @palette = VGA_PALETTE.dup
43
45
  @socket = TCPSocket.new('127.0.0.1', 19223)
44
46
  set_size(width, height)
45
47
  set_color_mode(color_mode) if color_mode
@@ -67,6 +69,9 @@ module Pixelflow
67
69
  raise "Invalid color mode: #{mode}"
68
70
  end
69
71
  @color_mode = mode
72
+ if mode == :palette
73
+ @palette = VGA_PALETTE.dup
74
+ end
70
75
  recreate_screen()
71
76
  @socket.write([2, COLOR_MODES[@color_mode]].pack('CC'))
72
77
  @socket.flush
@@ -122,6 +127,29 @@ module Pixelflow
122
127
  @last_timestamp = t
123
128
  end
124
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
+
125
153
  def set_color(r, g = 0, b = 0)
126
154
  @r = r
127
155
  @g = g
@@ -129,11 +157,15 @@ module Pixelflow
129
157
  end
130
158
 
131
159
  def set_palette(i, r, g, b)
132
- i = i % 256
133
- r = (r % 256) << 2
134
- g = (g % 256) << 2
135
- b = (b % 256) << 2
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
136
167
  @socket.write([3, i, r, g, b].pack('CCCCC'))
168
+ @socket.flush
137
169
  end
138
170
 
139
171
  def move_to(x, y)
@@ -452,6 +484,73 @@ module Pixelflow
452
484
  draw_line(x1, y1, x2, y2)
453
485
  draw_line(x2, y2, x0, y0)
454
486
  end
487
+
488
+ # FONT RENDERING
489
+ def self.load_font(font)
490
+ @@cypher_fonts ||= {}
491
+ return if @@cypher_fonts[font]
492
+ # STDERR.puts "Loading font from #{path}..."
493
+ font_data = {}
494
+ File.open(File.join(File.dirname(__FILE__), 'pixelflow_canvas', 'fonts', "#{font}.bdf")) do |f|
495
+ char = nil
496
+ f.each_line do |line|
497
+ if line[0, 9] == 'STARTCHAR'
498
+ char = {}
499
+ elsif line[0, 8] == 'ENCODING'
500
+ char[:encoding] = line.sub('ENCODING ', '').strip.to_i
501
+ elsif line[0, 7] == 'ENDCHAR'
502
+ font_data[char[:encoding]] = char
503
+ char = nil
504
+ elsif line[0, 3] == 'BBX'
505
+ parts = line.split(' ')
506
+ char[:width] = parts[1].to_i
507
+ char[:height] = parts[2].to_i
508
+ elsif line[0, 6] == 'BITMAP'
509
+ char[:bitmap] = []
510
+ else
511
+ if char && char[:bitmap]
512
+ char[:bitmap] << line.to_i(16)
513
+ end
514
+ end
515
+ end
516
+ end
517
+ @@cypher_fonts[font] = font_data
518
+ end
519
+
520
+ def draw_text(x, y, s, font, scale = 1)
521
+ Canvas.load_font(font)
522
+ dx = 0
523
+ s.each_char do |c|
524
+ glyph = @@cypher_fonts[font][c.ord]
525
+ if glyph
526
+ w = ((((glyph[:width] - 1) >> 3) + 1) << 3) - 1
527
+ (0...glyph[:height]).each do |iy|
528
+ (0...glyph[:width]).each do |ix|
529
+ if (((glyph[:bitmap][iy] >> (w - ix)) & 1) == 1)
530
+ (0...scale).each do |oy|
531
+ (0...scale).each do |ox|
532
+ set_pixel(x + (ix + dx) * scale + ox, y + iy * scale + oy)
533
+ end
534
+ end
535
+ end
536
+ end
537
+ end
538
+ dx += glyph[:width]
539
+ end
540
+ end
541
+ end
542
+
543
+ def self.text_width(s, font, options = {})
544
+ Canvas.load_font(font)
545
+ width = 0
546
+ s.each_char do |c|
547
+ glyph = @@cypher_fonts[font][c.ord]
548
+ if glyph
549
+ width += glyph[:width]
550
+ end
551
+ end
552
+ width
553
+ end
455
554
  end
456
555
 
457
556
  class Turtle
data/test-anaglyph.rb CHANGED
@@ -10,4 +10,6 @@ canvas.set_color(255, 0, 0)
10
10
  canvas.draw_line(10, 10, 100, 200)
11
11
 
12
12
  canvas.set_color(0, 255, 0)
13
- canvas.draw_line(20, 10, 90, 200)
13
+ canvas.draw_line(20, 10, 90, 200)
14
+
15
+ canvas.save_as_png('anaglyph.png')
data/test-sirds.rb CHANGED
@@ -10,7 +10,7 @@ width = 256
10
10
  height = 256
11
11
 
12
12
  canvas = Pixelflow::Canvas.new(width, height, :palette)
13
- (0...64).each { |i| canvas.set_palette(i, i, i, i) }
13
+ (0...64).each { |i| canvas.set_palette(i, i * 4, i * 4, i * 4) }
14
14
  (0...height).each do |y|
15
15
  (0...48).each do |x|
16
16
  canvas.set_pixel(x, y, rand(64))
@@ -34,3 +34,4 @@ end
34
34
  # end
35
35
  # end
36
36
 
37
+ canvas.save_as_png('sirds.png')
@@ -4,7 +4,6 @@ width = 256
4
4
  height = 256
5
5
 
6
6
  canvas = Pixelflow::Canvas.new(width, height, :palette)
7
- canvas.set_interpolation_mode(:bilinear)
8
7
  turtle = Pixelflow::Turtle.new(canvas)
9
8
  turtle.set_color(13)
10
9
 
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.2
4
+ version: 0.5.0
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-27 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:
@@ -22,11 +36,20 @@ files:
22
36
  - README.md
23
37
  - Rakefile
24
38
  - lib/pixelflow_canvas.rb
39
+ - lib/pixelflow_canvas/fonts/4x6.bdf
40
+ - lib/pixelflow_canvas/fonts/6x10.bdf
41
+ - lib/pixelflow_canvas/fonts/7x13.bdf
42
+ - lib/pixelflow_canvas/fonts/7x13B.bdf
43
+ - lib/pixelflow_canvas/fonts/8x13.bdf
44
+ - lib/pixelflow_canvas/fonts/8x13B.bdf
45
+ - lib/pixelflow_canvas/fonts/9x15.bdf
46
+ - lib/pixelflow_canvas/fonts/9x15B.bdf
25
47
  - lib/pixelflow_canvas/version.rb
48
+ - lib/pixelflow_canvas/vga_palette.rb
26
49
  - sig/pixelflow_canvas.rbs
27
50
  - test-anaglyph.rb
28
- - test-draw.rb
29
51
  - test-sirds.rb
52
+ - test-triangle.rb
30
53
  - test-turtle.rb
31
54
  - test.rb
32
55
  homepage: https://github.com/specht/pixelflow_canvas_ruby