#!ruby -w # simple vector-based paint program -- by ambrus # def mainloop; at_exit do print "\e[?9l\e[m"; system(*%w"stty sane"); end; system(*%w"stty -icanon -echo -echonl"); puts "\e[?9h"; render; while c = STDIN.getc; if ?\e != c; gotkey c; elsif ?[ != STDIN.getc || ?M != STDIN.getc; else b = STDIN.getc - ?\ ; x = STDIN.getc - ?!; y = STDIN.getc - ?!; gotmouse b, x, y; end; end; end; def render; print "\e[H"; @SCRHEI.times do |y| b = [[1e6]]; (0 ... @x.size).each do |obj| px = @x[obj]; py = @y[obj]; b.concat((0 ... px.size).map do |k| m = if py[k-1] <= y && y < py[k]; 1; elsif py[k] <= y && y < py[k-1]; -1; end; if m; if xdet = py[k] - py[k - 1]; x = (px[k-1] * (py[k] - y) - px[k] * (py[k - 1] - y)) / xdet; [x, m, obj]; end; end; end.compact); end; b.sort!; c = @x.map { 0 }; @SCRWID.times do |x| while b[0][0] < x; c[b[0][2]] += b[0][1]; b.shift; end; fobj = (0 ... c.size).map.reverse!.find {|o| 0 != c[o] }; colr = if fobj; @colr[fobj] else "7" end; print "\e[4#{colr}m "; end; y < @SCRHEI - 1 and print "\e[K\n"; end; print "\e[J"; STDOUT.flush; end; def fsave fname; File.open(fname, "w") do |file| file.puts "DRAWIMAGE 0 1"; (0 ... 26).each do |n| @x[n].empty? and next; file.print "OBJECT ", n, " ", @colr[n]; (0 ... @x[n].size).each do |k| file.print " ", @x[n][k], " ", @y[n][k]; end; file.print "\n"; end; end; end; def fload fname; file = (); begin file = File.open(fname); rescue Errno::ENOENT, Errno::ENAMETOOLONG, Errno::EISDIR, Errno::ELOOP, Errno::ENOTDIR, Errno::EACCES, Errno::EROFS; return; end; version = false; file.each do |l| l =~ /\A\s*(?:#|\z)/ and next; f = l.scan(/\S+/); case f[0].upcase; when "DRAWIMAGE"; "0" == f[1] or fail "wrong major verson loading image file"; version = true; when "OBJECT"; (0 ... 26) === (n = Integer(f[1])) or fail "wrong file format: invalid obj nr"; (0 ... 7) === (colr = Integer(f[2])) or fail "wrong file format: invalid colr"; @colr[n] = colr.to_s; s = (f.size - 3)/2; (0 ... s).each do |k| (-32768 .. 32767) === (@x[n][k] = Integer(f[3 + k * 2])) or fail "wrong file format: invalid coordinate"; (-32768 .. 32767) === (@y[n][k] = Integer(f[3 + k * 2 + 1])) or fail "wrong file format: invalid coordinate"; end; when "QC"; # noop else fail "wrong file format: invalid decl"; end; end; version or fail "wrong draw file format: no header"; file.close; true; end; TIOCGWINSZ = 0x00005413; def getwinsz; #@SCRHEI, @SCRWID = 24, 80; STDOUT.ioctl(TIOCGWINSZ, (buf = [].pack("x99"))); @SCRHEI, @SCRWID = buf.unpack("s!s!"); end; getwinsz; @x = (0 ... 26).map { [] }; @y = @x.map { [] }; @colr = @x.map { "0" }; def selobj n; @s = n; @xs = @x[n]; @ys = @y[n]; end; selobj 0; $*.empty? or fload($*[0]); def gotmouse b, x, y; if 0 == b; # left button appends point @xs.push x; @ys.push y; elsif 2 === b; # right button removes point @xs.pop; @ys.pop; elsif 1 === b; # middle button moves last point @xs.empty? and return; @xs[@xs.size - 1] = x; @ys[@xs.size - 1] = y; end; render; end; def gotkey c; case c; when ?a .. ?z; selobj c - ?a; when ?0 .. ?7; @colr[@s] = c.chr; when ?\b, ?\x7f; @xs.replace []; @ys.replace []; when ?,; @xs.empty? and return; @xs.unshift @xs.pop; @ys.unshift @ys.pop; when ?.; @xs.empty? and return; @xs.push @xs.shift; @ys.push @ys.shift; when ?/; @xs.pop; @ys.pop; when ?\cd; $*.empty? or fsave($*[0]); exit; end; render; end; mainloop(); __END__