From 002da6df444de0598d225d341d02d779e2480998 Mon Sep 17 00:00:00 2001 From: Gwenhael Le Moine Date: Thu, 20 Jul 2023 16:27:38 +0200 Subject: [PATCH] experiment with drawille to display LCD + improving LCD --- bin/rpl | 6 ++-- lib/rpl/interpreter.rb | 8 ++--- lib/rpl/types/grob.rb | 24 ++++++++++++++- lib/rpl/words/graphics.rb | 65 ++++++++++++++++++++++++++------------- rpl.gemspec | 2 ++ 5 files changed, 76 insertions(+), 29 deletions(-) diff --git a/bin/rpl b/bin/rpl index 5b47f35..be509d0 100755 --- a/bin/rpl +++ b/bin/rpl @@ -60,7 +60,7 @@ class RplRepl end end - print_display if @interpreter.show_display + print_lcd if @interpreter.show_lcd print_stack rescue Interrupt @@ -70,8 +70,8 @@ class RplRepl end end - def print_display - puts @interpreter.display_grob.to_text + def print_lcd + puts @interpreter.lcd_grob.to_braille end def print_stack diff --git a/lib/rpl/interpreter.rb b/lib/rpl/interpreter.rb index f4e68b7..81e0c88 100644 --- a/lib/rpl/interpreter.rb +++ b/lib/rpl/interpreter.rb @@ -12,19 +12,19 @@ class Interpreter include Types attr_reader :stack, - :display_grob, + :lcd_grob, :dictionary, :version - attr_accessor :show_display + attr_accessor :show_lcd def initialize( stack: [], dictionary: Dictionary.new ) @dictionary = dictionary @stack = stack - @show_display = false + @show_lcd = false - @display_grob = RplGrOb.new( 'GROB:131:64:0' ) + @lcd_grob = RplGrOb.new( 'GROB:131:64:0' ) end def run!( input ) diff --git a/lib/rpl/types/grob.rb b/lib/rpl/types/grob.rb index 37e5b43..c47e50d 100644 --- a/lib/rpl/types/grob.rb +++ b/lib/rpl/types/grob.rb @@ -1,5 +1,7 @@ # frozen_string_literal: true +require 'drawille' + require 'rpl/parser' class BitArray @@ -82,8 +84,28 @@ module Types .gsub( '1', '.' ) end + def to_braille + canvas = Drawille::Canvas.new + + @height.times do |y| + @width.times do |x| + canvas[x, y] = @bits[ ( y * @height ) + x ] == 1 + end + end + + canvas.frame + end + + def get_pixel( pos_x, pos_y ) + @bits[ ( pos_y * @height ) + pos_x ] + end + def set_pixel( pos_x, pos_y, value ) - @bits[ ( pos_y * @height ) + pos_x ] = value + @bits[ ( pos_y * @height ) + pos_x ] = value.to_i.zero? ? 0 : 1 + end + + def clear + @bits.from_i( 0 ) end end end diff --git a/lib/rpl/words/graphics.rb b/lib/rpl/words/graphics.rb index 3b5b2ce..e63fc36 100644 --- a/lib/rpl/words/graphics.rb +++ b/lib/rpl/words/graphics.rb @@ -37,64 +37,64 @@ module RplLang @stack << RplString.new( "\"#{args[0].bits.to_s(2).scan(/.{1,#{args[0].width}}/).join("\n")}\"" ) end ) - category = 'Display management and manipulation' + category = 'Lcd management and manipulation' - @dictionary.add_word!( ['displayon'], + @dictionary.add_word!( ['lcdon'], category, - '( -- ) display display', + '( -- ) display lcd', proc do - @show_display = true + @show_lcd = true end ) - @dictionary.add_word!( ['displayoff'], + @dictionary.add_word!( ['lcdoff'], category, - '( -- ) hide display', + '( -- ) hide lcd', proc do - @show_display = false + @show_lcd = false end ) - @dictionary.add_word!( ['displaywidth'], + @dictionary.add_word!( ['lcdwidth'], category, '( -- i ) put framebuffer\'s width on stack', proc do - @stack << RplNumeric.new( @display_grob.width ) + @stack << RplNumeric.new( @lcd_grob.width ) end ) - @dictionary.add_word!( ['displayheight'], + @dictionary.add_word!( ['lcdheight'], category, '( -- i ) put framebuffer\'s height on stack', proc do - @stack << RplNumeric.new( @display_grob.height ) + @stack << RplNumeric.new( @lcd_grob.height ) end ) - @dictionary.add_word!( ['→displaywidth', '->displaywidth'], + @dictionary.add_word!( ['→lcdwidth', '->lcdwidth'], category, '( i -- ) set framebuffer\'s width', proc do args = stack_extract( [[RplNumeric]] ) - @display_grob.width = args[0].value.to_i + @lcd_grob.width = args[0].value.to_i end ) - @dictionary.add_word!( ['→displayheight', '->displayheight'], + @dictionary.add_word!( ['→lcdheight', '->lcdheight'], category, '( i -- ) set framebuffer\'s height', proc do args = stack_extract( [[RplNumeric]] ) - @display_grob.height = args[0].value.to_i + @lcd_grob.height = args[0].value.to_i end ) - @dictionary.add_word!( ['display→', 'display->'], + @dictionary.add_word!( ['lcd→', 'lcd->'], category, '( -- g ) export framebuffer to GrOb', proc do - @stack << RplGrOb.new( @display_grob ) + @stack << RplGrOb.new( @lcd_grob ) end ) - @dictionary.add_word!( ['→display', '->display'], + @dictionary.add_word!( ['→lcd', '->lcd'], category, '( g -- ) import GrOb into framebuffer', proc do args = stack_extract( [[RplGrOb]] ) - @display_grob = RplGrOb.new( args[0] ) + @lcd_grob = RplGrOb.new( args[0] ) end ) @dictionary.add_word!( ['pixon'], @@ -106,7 +106,7 @@ module RplLang x = args[1].value.to_i y = args[0].value.to_i - @display_grob.set_pixel(x, y, 1) + @lcd_grob.set_pixel(x, y, 1) end ) @dictionary.add_word!( ['pixoff'], category, @@ -117,7 +117,30 @@ module RplLang x = args[1].value.to_i y = args[0].value.to_i - @display_grob.set_pixel(x, y, 0) + @lcd_grob.set_pixel(x, y, 0) # FIXME: toggle pixel instead of turning it off + end ) + @dictionary.add_word!( ['pix?'], + category, + '( x y -- b ) return boolean state of pixel at x y coordinates', + proc do + args = stack_extract( [[RplNumeric], [RplNumeric]] ) + + x = args[1].value.to_i + y = args[0].value.to_i + + @stack << RplBoolean.new( @lcd_grob.get_pixel(x, y) == 1 ) + end ) + + @dictionary.add_word!( ['blank'], + category, + '( w h -- g ) create an empty GrOb', + proc do + args = stack_extract( [[RplNumeric], [RplNumeric]] ) + + w = args[1].value.to_i + h = args[0].value.to_i + + @stack << RplGrOb.new( "GROB:#{w}:#{h}:0" ) end ) end end diff --git a/rpl.gemspec b/rpl.gemspec index 5657f9e..4880496 100644 --- a/rpl.gemspec +++ b/rpl.gemspec @@ -46,6 +46,8 @@ Gem::Specification.new do |s| 'lib/rpl/words/time-date.rb', 'lib/rpl/words/trig.rb'] + s.add_dependency 'drawille' + s.executables << 'rpl' s.required_ruby_version = '> 2.7'