;;; -*- Mode:LISP; Package:(PAINT GLOBAL); Base:10; Readtable:ZL -*- ;;;; Extended Graphics Routines for Paint ;;; LMI -- EFH (defmacro define-pattern (name &body rows) `(defconst ,name (make-pattern ,@rows))) (defun make-pattern (&rest rows) (let ((array (make-array '(8 32) :type 'art-1b))) (loop for y from 0 for row in rows do (loop for x from 0 to 31 do (aset (load-byte row (mod x 8) 1) array y x))) array)) (define-pattern black #b11111111 #b11111111 #b11111111 #b11111111 #b11111111 #b11111111 #b11111111 #b11111111) (define-pattern white #b00000000 #b00000000 #b00000000 #b00000000 #b00000000 #b00000000 #b00000000 #b00000000) (define-pattern light-gray #b00010001 #b01000100 #b00010001 #b01000100 #b00010001 #b01000100 #b00010001 #b01000100) (define-pattern gray #b01010101 #b10101010 #b01010101 #b10101010 #b01010101 #b10101010 #b01010101 #b10101010) (define-pattern dark-gray #b11101110 #b10111011 #b11101110 #b10111011 #b11101110 #b10111011 #b11101110 #b10111011) (define-pattern hline #b11111111 #b00000000 #b00000000 #b00000000 #b11111111 #b00000000 #b00000000 #b00000000) (define-pattern vline #b10001000 #b10001000 #b10001000 #b10001000 #b10001000 #b10001000 #b10001000 #b10001000) (define-pattern bar-sinister #b00010001 #b00100010 #b01000100 #b10001000 #b00010001 #b00100010 #b01000100 #b10001000) (define-pattern bar-dexter #b10001000 #b01000100 #b00100010 #b00010001 #b10001000 #b01000100 #b00100010 #b00010001) (define-pattern checks #b11110000 #b11110000 #b11110000 #b11110000 #b00001111 #b00001111 #b00001111 #b00001111) (define-pattern grids #b10001000 #b10001000 #b10001000 #b11111111 #b10001000 #b10001000 #b10001000 #b11111111) (define-pattern dots #b10001000 #b00000000 #b00000000 #b00000000 #b10001000 #b00000000 #b00000000 #b00000000) (define-pattern scales #b10000000 #b10000000 #b01000001 #b00111110 #b00001000 #b00001000 #b00010100 #b11100011) ;(defmacro defbrush (name &body rows) ; `(defvar ,name ; (make-array 8 :type 'art-8b ; :initial-contents ; ',rows))) (define-pattern small-round-brush #b00000000 #b00000000 #b00011000 #b00111100 #b00111100 #b00011000 #b00000000 #b00000000) (define-pattern large-round-brush #b00111100 #b01111110 #b11111111 #b11111111 #b11111111 #b11111111 #b01111110 #b00111100) (define-pattern small-square-brush #b00000000 #b00000000 #b00111100 #b00111100 #b00111100 #b00111100 #b00000000 #b00000000) (define-pattern large-square-brush #b11111111 #b11111111 #b11111111 #b11111111 #b11111111 #b11111111 #b11111111 #b11111111) (define-pattern horizontal-brush #b00000000 #b00000000 #b00000000 #b11111111 #b11111111 #b00000000 #b00000000 #b00000000) (define-pattern vertical-brush #b00011000 #b00011000 #b00011000 #b00011000 #b00011000 #b00011000 #b00011000 #b00011000) (define-pattern diagonal-brush #b10000000 #b11000000 #b01100000 #b00110000 #b00011000 #b00001100 #b00000110 #b00000011) (defstruct (rectangle :named (:conc-name "RECT-") (:constructor %make-rect)) "A rectangle" (top 0) (left 0) (bottom 0) (right 0) (height 0) (width 0)) (defun make-rect (&key (top 0) (left 0) (bottom nil) (right nil) (height 0) (width 0)) (let ((b (or bottom (+ top height))) (r (or right (+ left width)))) (%make-rect :top top :left left :bottom b :right r :width (- r left) :height (- b top)))) (defmacro with-rect ((top l b r w h) rect &body body) (once-only (rect) `(let (,@(if top `((,top (rect-top ,rect)))) ,@(if l `((,l (rect-left ,rect)))) ,@(if b `((,b (rect-bottom ,rect)))) ,@(if r `((,r (rect-right ,rect)))) ,@(if w `((,w (rect-width ,rect)))) ,@(if h `((,h (rect-height ,rect))))) ,@body))) (defun set-rect (rect top left bottom right) (setf (rect-top rect) top) (setf (rect-left rect) left) (setf (rect-bottom rect) bottom) (setf (rect-right rect) right) (setf (rect-width rect) (- right left)) (setf (rect-height rect) (- bottom top))) (defmacro within-rect-p (x y top left bottom right) (once-only (x y) `(and (> ,x ,left) (> ,y ,top) (< ,x ,right) (< ,y ,bottom)))) (defun within-rect? (x y rect) (within-rect-p x y (rect-top rect) (rect-left rect) (rect-bottom rect) (rect-right rect))) (defun rect-select (x y top left width h v) (+ (fix (// (- x left) h)) (* (fix (// width h)) (fix (// (- y top) v))))) (defun clear-rect-shadowed (window rect &optional (shadow-thickness 3)) (with-rect (top left nil nil width height) rect (send window :draw-rectangle width height left top tv:alu-andca) (send window :draw-rectangle width 1 (1- left) (1- top) tv:alu-ior) (send window :draw-rectangle 1 height (1- left) (1- top) tv:alu-ior) (send window :draw-rectangle (+ shadow-thickness width) shadow-thickness (1- left) (+ top height) tv:alu-ior) (send window :draw-rectangle shadow-thickness (+ shadow-thickness height) (+ left width) (1- top) tv:alu-ior))) (defun frame-rect (width height x y sheet alu thick) (tv:prepare-sheet (sheet) (tv:%draw-rectangle-clipped (- width thick) thick x y alu sheet) (tv:%draw-rectangle-clipped thick (- height thick) (- (+ width x) thick) y alu sheet) (tv:%draw-rectangle-clipped (- width thick) thick (+ x thick) (- (+ y height) thick) alu sheet) (tv:%draw-rectangle-clipped thick (- height thick) x (+ y thick) alu sheet))) (defun good-array-width (width) (* (ceiling (// width 32.0s0)) 32)) ;;; This is not fast enough ;;; there might be some way to get rid of the multiplies ;;; maybe this should use draw-wide-curve??? (defmacro draw-point (x-form y-form) `(progn (setq x-val ,x-form y-val ,y-form) (as-2-reverse (boole alu -1 (ar-2-reverse screen-array x-val y-val)) screen-array x-val y-val))) (defun frame-ellipse (width height left top sheet alu thick) thick (unless (or (zerop width) (zerop height)) (tv:prepare-sheet (sheet) (let* ((radius (// width 2)) (e (small-float (// (float width) (float height)))) (cx (fixr (+ left radius))) (cy (fixr (+ top (// height 2)))) (screen-array (send sheet :screen-array)) (x 0) (y (fixr (// radius e))) (e^2 (^ e 2)) (4*e2 (* 4 e^2)) (m4e2 (- 4*e2)) (6*e2 (* 6 e^2)) (6+4e2 (+ 6 4*e2)) (4+6e2 (+ 4 6*e2)) (d (+ 2 e^2 (* -2 e radius))) (f (fix (* radius (// e (sqrt (1+ e^2)))))) ;this is the point where the slope becomes < -1 x-val y-val) (do () ((= x f)) (draw-point (+ cx x) (+ cy y)) (draw-point (+ cx x) (- cy y)) (draw-point (- cx x) (- cy y)) (draw-point (- cx x) (+ cy y)) (if (minusp d) (setq d (+ d (* 4 x) 6)) ;inc x (setq d (+ d (* 4 x) (* m4e2 y) 6+4e2)) ;inc x, dec y (decf y)) (incf x)) (setq x radius) (setq y 0) (setq d (+ 1 (* -2 radius) (* -2 e^2))) (do () ((< x f)) (draw-point (+ cx x) (+ cy y)) (draw-point (+ cx x) (- cy y)) (draw-point (- cx x) (- cy y)) (draw-point (- cx x) (+ cy y)) (if (minusp d) (setq d (+ d (* 4*e2 y) 6*e2)) ;inc y (setq d (+ d (* -4 x) (* 4*e2 y) 4+6e2)) ;inc y, dec x (decf x)) (incf y)))))) (defun solid-ellipse (width height left top sheet pattern alu) (unless (or (zerop width) (zerop height)) (tv:prepare-sheet (sheet) (let* ((radius (// width 2)) (e (small-float (// (float width) (float height)))) (cx (fixr (+ left radius))) (cy (fixr (+ top (// height 2)))) (screen-array (send sheet :screen-array)) (x radius) (y 0) (e^2 (^ e 2)) (4*e2 (* 4 e^2)) (m4e2 (- 4*e2)) (6*e2 (* 6 e^2)) (6+4e2 (+ 6 4*e2)) (4+6e2 (+ 4 6*e2)) (d (+ 1 (* -2 radius) (* -2 e^2))) (f (fix (* radius (// e (sqrt (1+ e^2)))))) ;this is the point where the slope becomes < -1 (last-y y) last-x w h from-y from-x from-x-r to-y to-x to-x-r) (do () ((< x f)) (if (minusp d) (setq d (+ d (* 4*e2 y) 6*e2)) ;inc y (setq d (+ d (* -4 x) (* 4*e2 y) 4+6e2)) ;inc y, dec x (setq w (* 2 x) h (- y last-y)) ;draw the rectangles when x changes (setq to-x (- cx x) from-x (mod to-x 8)) (setq to-y (- cy y) from-y (mod to-y 8)) (bitblt alu w h pattern from-x from-y screen-array to-x to-y) (setq to-y (+ cy last-y) from-y (mod to-y 8)) (bitblt alu w h pattern from-x from-y screen-array to-x to-y) (setq last-y y) (decf x)) (incf y)) (setq y (fixr (// radius e))) (setq x 0) (setq last-x x) (setq d (+ 2 e^2 (* -2 e radius))) (do () ((<= y last-y)) ; (setq w (- y last-y)) ; (format t "~a " w) (if (minusp d) (setq d (+ d (* 4 x) 6)) ;inc x (setq d (+ d (* 4 x) (* m4e2 y) 6+4e2)) ;inc x, dec y (setq w (- x last-x) h (- y last-y)) ;draw the rectangles when y changes (setq to-y (- cy y) from-y (mod to-y 8)) (setq to-x (- cx x) from-x (mod to-x 8)) (setq to-x-r (+ cx last-x) from-x-r (mod to-x-r 8)) (bitblt alu w h pattern from-x from-y screen-array to-x to-y) (bitblt alu w h pattern from-x-r from-y screen-array to-x-r to-y) (setq to-y (+ cy last-y) from-y (mod to-y 8)) (bitblt alu w h pattern from-x from-y screen-array to-x to-y) (bitblt alu w h pattern from-x-r from-y screen-array to-x-r to-y) (setq last-x x) (decf y)) (incf x)))))) (defvar *x-array* (make-array 2)) (defvar *y-array* (make-array 2)) (defun draw-wide-line (x1 y1 x2 y2 width window &optional (alu (send window :char-aluf))) (aset x1 *x-array* 0) (aset x2 *x-array* 1) (aset y1 *y-array* 0) (aset y2 *y-array* 1) (send window :draw-wide-curve *x-array* *y-array* width 2 alu)) (defvar *mixing-array* (make-array '(8 32) :type 'art-1b)) (defun daub (x y pattern brush sheet) (tv:prepare-sheet (sheet) (let ((screen-array (send sheet :screen-array))) (bitblt tv:alu-seta 8 8 pattern (mod x 8) (mod y 8) *mixing-array* 0 0) (bitblt tv:alu-and 8 8 brush 0 0 *mixing-array* 0 0) (bitblt tv:alu-andca 8 8 brush 0 0 screen-array x y) (bitblt tv:alu-ior 8 8 *mixing-array* 0 0 screen-array x y)))) (defun stroke (from-x from-y to-x to-y pattern brush sheet) (let* ((dx (- to-x from-x)) (dy (- to-y from-y)) (long (max (abs dx) (abs dy))) (short (min (abs dx) (abs dy))) (s (// long 2)) (screen-array (send sheet :screen-array))) (if (zerop long) (daub from-x from-y pattern brush sheet) (tv:prepare-sheet (sheet) (if (= long (abs dx)) (loop with ypos = from-y with sdy = (signum dy) repeat long for xpos from from-x by (signum dx) do (when (minusp (decf s short)) (incf ypos sdy) (incf s long)) doing (bitblt tv:alu-seta 8 8 pattern (mod xpos 8) (mod ypos 8) *mixing-array* 0 0) (bitblt tv:alu-and 8 8 brush 0 0 *mixing-array* 0 0) (bitblt tv:alu-andca 8 8 brush 0 0 screen-array xpos ypos) (bitblt tv:alu-ior 8 8 *mixing-array* 0 0 screen-array xpos ypos)) (loop with xpos = from-x with sdx = (signum dx) repeat long for ypos from from-y by (signum dy) do (when (minusp (decf s short)) (incf xpos sdx) (incf s long)) doing (bitblt tv:alu-seta 8 8 pattern (mod xpos 8) (mod ypos 8) *mixing-array* 0 0) (bitblt tv:alu-and 8 8 brush 0 0 *mixing-array* 0 0) (bitblt tv:alu-andca 8 8 brush 0 0 screen-array xpos ypos) (bitblt tv:alu-ior 8 8 *mixing-array* 0 0 screen-array xpos ypos)))))))