commit ab79d7fbe27d4097ee7f8c87f35a9f22b01924e5
parent fd5b26f367ffc566100218a2e065b5408c9e8d61
Author: Tomas Hlavaty <tom@logand.com>
Date: Sun, 20 Sep 2015 18:17:08 +0200
linux framebuffer experiment
Diffstat:
A | fb.lisp | | | 254 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
1 file changed, 254 insertions(+), 0 deletions(-)
diff --git a/fb.lisp b/fb.lisp
@@ -0,0 +1,254 @@
+;;; Copyright (C) 2015 Tomas Hlavaty <tom@logand.com>
+;;;
+;;; Permission is hereby granted, free of charge, to any person
+;;; obtaining a copy of this software and associated documentation
+;;; files (the "Software"), to deal in the Software without
+;;; restriction, including without limitation the rights to use, copy,
+;;; modify, merge, publish, distribute, sublicense, and/or sell copies
+;;; of the Software, and to permit persons to whom the Software is
+;;; furnished to do so, subject to the following conditions:
+;;;
+;;; The above copyright notice and this permission notice shall be
+;;; included in all copies or substantial portions of the Software.
+;;;
+;;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+;;; EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+;;; MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+;;; NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+;;; HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+;;; WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+;;; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+;;; DEALINGS IN THE SOFTWARE.
+
+(defpackage :rw.fb
+ (:use :cl))
+
+(in-package :rw.fb)
+
+;; (defun fbset ()
+;; (rw.os:with-program-output (s "fbset")
+;; (rw:till (rw:peek-reader (rw:char-reader s)))))
+;; fbset is in busybox which breaks everything for me
+;;(fbset)
+
+;; $ fbset
+;;
+;; mode "1366x768-0"
+;; # D: 0.000 MHz, H: 0.000 kHz, V: 0.000 Hz
+;; geometry 1366 768 1366 768 32
+;; timings 0 0 0 0 0 0 0
+;; accel true
+;; rgba 8/16,8/8,8/0,0/0
+;; endmode
+
+(defun make-canvas (stream screen-width screen-height)
+ (declare (type fixnum screen-width screen-height))
+ (let ((buffer (make-array (* 4 screen-width screen-height)
+ :element-type '(unsigned-byte 8)
+ :initial-element 0))
+ (font (rw.psf::load-font
+ ;;"/nix/store/sxrgxk6bw27c516zdvjh2mr6nk4hl9ni-terminus-font-4.39/share/consolefonts/ter-g28n.psf.gz"
+ ;;"/nix/store/sxrgxk6bw27c516zdvjh2mr6nk4hl9ni-terminus-font-4.39/share/consolefonts/ter-g28b.psf.gz"
+ ;;"/nix/store/3jzf1724gfkg942i8dbg0ixdncsv0qhf-kbd-2.0.3/share/consolefonts/default8x16.psfu.gz"
+ "/nix/store/3jzf1724gfkg942i8dbg0ixdncsv0qhf-kbd-2.0.3/share/consolefonts/Lat2-Terminus16.psfu.gz"
+ )))
+ (lambda (form)
+ (let ((*x* 0)
+ (*y* 0)
+ (*fa* #xff)
+ (*fr* #xaf)
+ (*fg* #xaf)
+ (*fb* #xaf)
+ (*ba* #xff)
+ (*br* 0)
+ (*bg* 0)
+ (*bb* 0))
+ (declare (special *x* *y* *fa* *fr* *fg* *fb* *ba* *br* *bg* *bb*))
+ (labels ((pixel (x y a r g b)
+ (let ((i (* 4 (+ x (* y screen-width)))))
+ (setf (aref buffer i) b
+ (aref buffer (1+ i)) g
+ (aref buffer (+ 2 i)) r
+ (aref buffer (+ 3 i)) a)))
+ (lineto (x y)
+ (let* ((x1 (min *x* x))
+ (x2 (max *x* x))
+ (y1 (min *y* y))
+ (y2 (max *y* y))
+ (dx (- x2 x1))
+ (dy (- y2 y1)))
+ (if (< dx dy)
+ (loop
+ for y from y1 to y2
+ do (pixel (if (plusp dx)
+ (round (+ x1 (/ (* dy (- y y1)) dx)))
+ x1)
+ y
+ *fa* *fr* *fg* *fb*))
+ (loop
+ for x from x1 to x2
+ do (pixel x
+ (if (plusp dy)
+ (round (+ y1 (/ (* dx (- x x1)) dy)))
+ y1)
+ *fa* *fr* *fg* *fb*))))
+ (setq *x* x
+ *y* y))
+ (bitmap (bitmap)
+ (loop
+ for v across bitmap
+ for y = *y* then (1+ y)
+ do (loop
+ for bit across v
+ for x = *x* then (1+ x)
+ do (if (zerop bit)
+ (pixel x y *ba* *br* *bg* *bb*)
+ (pixel x y *fa* *fr* *fg* *fb*)))))
+ (chara (c)
+ (let ((n (char-code c)))
+ (if (<= 1 n #x7f)
+ (bitmap (aref (rw.psf::psf2-bitmaps font) n))
+ (let ((*fr* 0)
+ (*br* 255))
+ (declare (special *fr* *br*))
+ (bitmap (aref (rw.psf::psf2-bitmaps font)
+ #.(char-code #\?))))))
+ (incf *x* (rw.psf::header-width (rw.psf::psf2-header font))))
+ (rec (f)
+ (if (atom f)
+ (typecase f
+ (string
+ (loop
+ for c across f
+ do (chara c))))
+ (let* ((h (car f))
+ (b (cdr f))
+ (e (if (consp h) (car h) h))
+ (a (when (consp h) (cdr h))))
+ (ecase e
+ (:<text
+ (mapc #'rec b))
+ (:body
+ (mapc #'rec b))
+ (:circle)
+ (:div
+ (mapc #'rec b))
+ (:font-preview
+ (destructuring-bind () a
+ (let ((r (rw:reader (rw.psf::psf2-bitmaps font)))
+ (h (rw.psf::psf2-header font))
+ (x *x*))
+ (assert (eql 256 (rw.psf::header-length h)))
+ (dotimes (i 16)
+ (setq *x* x)
+ (incf *y* (rw.psf::header-height h))
+ (dotimes (j 16)
+ (incf *x* (rw.psf::header-width h))
+ (bitmap (rw:next r)))))))
+ (:h1
+ (let ((*fr* #xff)
+ (*fg* #xff)
+ (*fb* #xff))
+ (declare (special *fr* *fg* *fb*))
+ (rec "* ")
+ (mapc #'rec b)))
+ (:h2
+ (let ((*fr* #xcf)
+ (*fg* #xcf)
+ (*fb* #xcf))
+ (declare (special *fr* *fg* *fb*))
+ (rec "** ")
+ (mapc #'rec b)))
+ (:h3
+ (let ((*fr* #x8f)
+ (*fg* #x8f)
+ (*fb* #x8f))
+ (declare (special *fr* *fg* *fb*))
+ (rec "*** ")
+ (mapc #'rec b)))
+ (:h4
+ (let ((*fr* #x4f)
+ (*fg* #x4f)
+ (*fb* #x4f))
+ (declare (special *fr* *fg* *fb*))
+ (rec "**** ")
+ (mapc #'rec b)))
+ (:html
+ (mapc #'rec b))
+ (:line
+ (destructuring-bind (&key x1 y1 x2 y2 &allow-other-keys) a
+ (setq *x* x1
+ *y* y1)
+ (lineto x2 y2)))
+ (:p
+ (mapc #'rec b))
+ (:polyline
+ (destructuring-bind (&key points &allow-other-keys) a
+ (loop
+ with to = nil
+ with r = (rw:peek-reader (rw:reader points))
+ while (progn
+ (rw:skip r)
+ (rw:peek r))
+ do (let* ((x (rw:next-z0 r))
+ (y (progn
+ (rw:skip r)
+ (assert (eql #\, (rw:next r)))
+ (rw:skip r)
+ (rw:next-z0 r))))
+ (when to
+ (lineto x y))
+ (setq *x* x
+ *y* y
+ to t)))))
+ (:rect
+ (destructuring-bind (&key x y width height &allow-other-keys) a
+ (setq *x* x
+ *y* y)
+ (dotimes (i width)
+ (dotimes (j height)
+ (pixel (+ *x* i) (+ *y* j) *fa* *fr* *fg* *fb*)))))
+ (:span
+ (mapc #'rec b))
+ (:svg
+ (mapc #'rec b))
+ (:text
+ (destructuring-bind (&key x y &allow-other-keys) a
+ (setq *x* x
+ *y* y)
+ (mapc #'rec b))))))))
+ (rec form)))
+ (write-sequence buffer stream))))
+
+(defun test (&key (device "/dev/fb0") (width 1376 #+nil 1366) (height 768))
+ (with-open-file (s device
+ :direction :output
+ :if-exists :overwrite
+ :if-does-not-exist :error
+ :element-type '(unsigned-byte 8))
+ (let ((fb (make-canvas s width height)))
+ (funcall fb
+ '(:html
+ (:body
+ (:h1 "Heading 1")
+ (:h2 "Heading 2")
+ (:h3 "Heading 3")
+ (:h4 "Heading 4")
+ (:p "This is the first paragraph.")
+ (:p "This is the second paragraph with non-ascii character: รค")
+ (:svg
+ ((:rect :x 0 :y 20 :width 20 :height 20 :fill "lime"
+ :stroke-width 4 :stroke "pink"))
+ ((:circle :cx 125 :cy 125 :r 75 :fill "orange"))
+ ((:polyline :points "50,150 50,200 200,200 200,100"
+ :stroke "red" :stroke-width 4 :fill "none"))
+ ((:line :x1 50 :y1 50 :x2 200 :y2 200 :stroke "blue"
+ :stroke-width 4))
+ ((:text :x 250 :y 150 :font-family "Verdana" :font-size 55)
+ "This is a SVG text element.")
+ (:font-preview)))))
+ (file-position s 0)
+ (funcall fb "hi")))
+ (values))
+
+;;(time (test))