;;; -*- Mode:LISP; Package:PAINT; Base:10 -*- ;; ;; Paint A perq painting program (similar to MacPaint) ;; ;; Semi-finalized version put together 4/21/85 ;; ;; Robert Rose ;; (format t "Loading Perq Paint system; please wait...~%") (load "press.sfasl") (in-package "PAINT" :use '("LISP" "VIEWPTUSER" "SAPPHUSER" "SAPPHDEFSDEFS" "ACCINTUSER" "ACCINTDEFS")) ; ; Definitions for the PAINT drawing program ; ; 'paintdef.slisp' ; (defvar *paintstuff*) ; global holder of paint information ; Some strings that are used in a lot of places (defvar *selcorner* "(L or R) -- Select A Corner M -- Back to Menu") ;; const (defvar *blank-line* " ") ; other variables (defvar *menu-pos-x* 600) (defvar *menu-other-pos-y* 500) (defvar *top-patt*) (defvar *patt-spacer* 74) (defvar *brush-w*) (defvar *brush-h*) (defvar *brush-x*) (defvar *brush-y*) ;brush positions (defvar *brush-64x*) (defvar *brush-32x*) (defvar *brush-16x*) (defvar *brush-8x*) (defvar *brush-64y*) (defvar *brush-32y*) (defvar *brush-16y*) (defvar *brush-8y*) (defvar *last-grid-x*) (defvar *last-grid-y*) (defvar *pattern-x*) (defvar *pattern-y*) (defvar *current-draw-fun*) (defvar *move-area-rop*) (defconstant LEFTDOWN 83) (defconstant LEFTUP 75) (defconstant RIGHTDOWN 84) (defconstant MIDDLEDOWN 82) (defconstant NOTHING 85) (defstruct paintstruct "This structure holds pertinant PAINT information" window ;the main window drawport ;drawings to here image ;the image on leaving off-view ;offscreen viewport off-whole ;offscreen viewport rot-view ;offscreen viewport font ;the current font (set to system font at first) pixels-x ;pixels across for image area pixels-y ;pixels down for image area screen-y ;pixels down for whole screen screen-x ;pixels across for whole screen grid-mod ;grid mod value ) ; ; 'paint.slisp' ; ; ; Asks user for confirmation ; (defun confirm (message) (makewinlistener *userwindow*) (setwindowtitle *userwindow* message ) (let ((answer (yes-or-no-p))) (setwindowtitle *userwindow* *blank-line*) answer)) ; ; Flash-area turns on then off a rectangular area bound by x1 y1, x2 y2. ; (defun half-flash (x1 y1 x2 y2 dp) (vpline dp :xorline x1 y1 x1 y2) (vpline dp :xorline x1 y1 x2 y1) (vpline dp :xorline x2 y1 x2 y2) (vpline dp :xorline x1 y2 x2 y2)) (defun flash-area (x1 y1 x2 y2 dp) (progn (half-flash x1 y1 x2 y2 dp) (half-flash x1 y1 x2 y2 dp))) ; ; Get the drawing viewport ready ; (defun prepare-drawport (title) (setwindowtitle (paintstruct-window *paintstuff*) title) (makewinlistener (paintstruct-window *paintstuff*)) (setlistener (paintstruct-drawport *paintstuff*)) (setcursorpos (paintstruct-drawport *paintstuff*) *last-grid-x* *last-grid-y*)) ;; ;; Allows the user to select a rectangle in the window and ;; highlights it while he is choosing returns LeftX,UpperY,Wid,Hgt, ;; (defun SelectWindowRegion (inwindow port) (let ((oldx 0) (oldy 0)) (setwindowtitle inwindow *Selcorner*) (multiple-value-bind (cm char y x) (get-points nil port) (declare (ignore char)) (setq oldx x oldy y) (cond ((= cm MIDDLEDOWN) nil) ((left-or-right cm) (setwindowtitle inwindow *Selcorner* ) (loop (multiple-value-bind (cm* char y* x*) (get-points t port) (declare (ignore char)) (when (or (/= oldx x*) (/= oldy y*)) (half-flash x y oldx oldy port) (setq oldx x* oldy y*) (half-flash x y x* y* port)) (cond ((left-or-right cm*) (half-flash x y x* y* port) (return (values (min x x*) (min y* y) (1+ (- (max x x*) (min x x*))) (1+ (- (max y y*) (min y y*)))))) ((= cm* MIDDLEDOWN) (half-flash x y x* y* port) (return nil)))))))))) ; ; If the left or right key was pressed; or a keyboard character. ; (defun left-or-right (key) (or (= key LEFTDOWN) (= key RIGHTDOWN))) ; ; Get-points returns where the puck was clicked ; If return-p is true, it returns after one scan regardless of what ; is pressed or not. If return-p is nil, get-points waits until you ; press something. ; ; Optional parameters are the x1, y1 x2,y2 broders you want to stay within; ; default is the whole screen (to the left of the menu stuff) ; (defmacro constrain (num modu) `(* ,modu (floor ,num ,modu))) (defun get-points (return-p vp &optional (xleft 0) (ytop 0) (xright (paintstruct-pixels-x *paintstuff*)) (ybot (paintstruct-pixels-y *paintstuff*))) (let ((gmod (paintstruct-grid-mod *paintstuff*)) (a nil) (b nil) (reg nil) (c nil) (d nil)) (loop (multiple-value-bind (a b reg c d) (getevent vp :keywaitdiffpos) (when (and (= 1 reg) (> d xleft) (> c ytop) (< d xright) (< c ybot)) (when (or (left-or-right a) (= a 0) (= a MIDDLEDOWN)) (return (values a b (constrain c gmod) (constrain d gmod)))) (when return-p (return (values a b (constrain c gmod) (constrain d gmod))))))))) (defun get-integer (message low high) (setwindowtitle *userwindow* message) (loop (let ((new (parse-integer (read-line) :junk-allowed t))) (when (and (not (null new)) (<= low new high )) (return new)) (princ "Illegal value, try again:") (force-output)))) ;; ; Let the user set the mouse jump value ;; (defun jump-choose () (makewinlistener *userwindow*) (let ((new (get-integer "Select mouse jump value; Greater than 0; Less than 100." 1 99))) (setf (paintstruct-grid-mod *paintstuff*) new) (setwindowtitle *userwindow* *blank-line*))) ; ; Output file error message ; (defun file-error () (princ "Illegal or nonexistent file.") (force-output)) ; ; Select-file asks the user for a file name in the lisp window. ; (defun select-file (message) (makewinlistener *userwindow*) (setwindowtitle *userwindow* message) (terpri) (let ((new-input (read-line))) (setwindowtitle *userwindow* *blank-line*) (if (= 0 (length new-input)) nil new-input))) ;; ; Let the user select a new KST font ;; (defun new-font (dp) (makewinlistener *userwindow*) (let ((file (select-file "Enter name of valid KST font file:"))) (if (null file) (file-error) (let ((f (loadfont dp file))) (if (= 0 f) (file-error) (setf (paintstruct-font *paintstuff*) f)))))) ; ; Primitive save and load functions ; ; Written by Skef ; (defun load-raw-bitmap (filename &optional (file-x 0) (file-y 0) (file-width (paintstruct-pixels-x *paintstuff*)) (x 0) (y 0) (width (paintstruct-pixels-x *paintstuff*)) (height (paintstruct-pixels-y *paintstuff*))) (multiple-value-bind (gr sap size) (sesameuser:subreadfile *sesport* filename) (cond ((= gr success) (putviewportrectangle (paintstruct-drawport *paintstuff*) *move-area-rop* x y width height (alien-sap sap) (ash size -1) (logand (ash (+ file-width 63) -4) (lognot 3)) file-x file-y) (invalidatememory kernelport (lisp::%sp-make-fixnum sap) size)) (t (format t "Couldn't read ~A." filename) (force-output) nil)))) (defun save-raw-bitmap (filename &optional (x 0) (y 0) (width (paintstruct-pixels-x *paintstuff*)) (height (paintstruct-pixels-y *paintstuff*))) (multiple-value-bind (available sap size) (getviewportrectangle (paintstruct-drawport *paintstuff*) x y width height 0 0) (cond ((and available (not (null size))) (sesameuser:subwritefile *sesport* filename (alien-sap sap) (ash size 1) 0) (invalidatememory kernelport (lisp::%sp-make-fixnum sap) (ash size 1))) (t (format t "Couldn't write the bits!") (force-output) nil)))) ; ; Load-file loads in a picture image ; (defun load-file () (let ((file (select-file "Enter name of PAINT image to load:"))) (if (null file) (file-error) (load-raw-bitmap (namestring (truename file)))))) ; ; Save-file saves out the whole screen ; (defun save-file () (let ((file (select-file "Enter name of PAINT image to save to:"))) (if (null file) (file-error) (save-raw-bitmap file)))) ; ; load-arb-file lets user choose the width ; (defun load-arb-file () (let ((file (select-file "Enter name of file to load from:"))) (if (null file) (file-error) (let ((x (get-integer "How many pixels across to start (x) :" 0 1024)) (y (get-integer "How many pixels down to start (y) :" 0 1024)) (width (get-integer "How many pixels on a line (width) :" 0 1024))) (load-raw-bitmap (namestring (truename file)) x y width) (setwindowtitle *userwindow* *blank-line*))))) ; ; Save-arb-file lets the user select the width and where to store (defun save-arb-file (dp) (let ((file (select-file "Enter name of file to save to:"))) (if (null file) (file-error) (let ((x (get-integer "How many pixels across to start (x) (-1 to use mouse):" -1 1024))) (cond ((= x -1) (prepare-drawport *selcorner*) (multiple-value-bind (x y width) (selectwindowregion (paintstruct-window *paintstuff*) dp) (save-raw-bitmap file x y width))) (t (let ((y (get-integer "How many pixels down to start (y) :" 0 1024)) (width (get-integer "How many pixels on a line (width) :" 0 1024))) (save-raw-bitmap file x y width)))))))) ; ; Press-file Makes a press file from the paint screen ; (defun press-file () (let ((file (select-file "Enter name of press file to save image to:"))) (if (null file) (file-error) (press:press-window file "paint" 0 0 (paintstruct-pixels-x *paintstuff*) (paintstruct-pixels-y *paintstuff*))))) ; ; Destroy-all-vp gets rid of all the viewports when we are done. ; (defun destroy-all-vp () (progn (destroyviewport (paintstruct-drawport *paintstuff*)) (destroyviewport (paintstruct-off-view *paintstuff*)) (destroyviewport (paintstruct-off-whole *paintstuff*)) (destroyviewport (paintstruct-rot-view *paintstuff*)) (deletewindow (paintstruct-window *paintstuff*)) (makunbound '*paintstuff*))) ; ; Do-functions gets the users choice and branches away. ; (defun do-functions () (let ((dp (paintstruct-drawport *paintstuff*)) (rop-x (+ 5 *menu-pos-x*)) (rop-y 680)) (loop (setwindowtitle (paintstruct-window *paintstuff*) "Select Option From Menu") (let* ((msjump (format nil "~a" (paintstruct-grid-mod *paintstuff*))) (fvp (getsysfont (windowviewport *userwindow*))) (duy (vpputcharray dp fvp :rrpl rop-x rop-y (concatenate 'string "Mouse Jump:" msjump " ") (+ 12 (length msjump)) 0 (+ 11 (length msjump)))) (duy (vpputcharray dp fvp :rrpl rop-x (+ 15 rop-y) (concatenate 'string "Draw ROP:" (case *current-draw-fun* (:DRAWLINE "Black ") (:ERASELINE "White ") (:XORLINE "Invert"))) 15 0 14)) (duy (vpputcharray dp fvp :rrpl rop-x (+ 30 rop-y) (concatenate 'string "Move/CHR ROP:" (case *move-area-rop* (:RRPL "Replc") (:RNOT "Not ") (:RAND "And ") (:RANDNOT "AndNt") (:ROR "Or ") (:ORNOT "OrNot") (:RXOR "XOr ") (:RXORNOT "XNor "))) 18 0 17)) (user-choice (if (pasted-menu-p "OPTIONS:") (pasted-menu-choose "OPTIONS:") (put-up-menu)))) (declare (ignore duy)) (case user-choice (1 (load-file)) (2 (save-file)) (24 (load-arb-file)) (25 (save-arb-file dp)) (26 (press-file)) (3 (prepare-drawport "(L or R) Turn On Painting Mode M -- Back to Menu") (painting dp)) (4 (prepare-drawport "(L or R) -- Select New Brush M -- Back to Menu") (select-brush dp)) (5 (prepare-drawport "(L or R) -- Select New Pattern M -- Back to Menu") (select-default dp)) (6 (prepare-drawport "(L or R) -- Turn On Drawing Mode M -- Back to Menu") (freehand dp)) (7 (prepare-drawport "(L or R) -- Start Line M -- Drawing Menu ") (make-line dp)) (8 (prepare-drawport "(L or R) -- Center of Circle M -- Back to Menu ") (make-circle dp)) (9 (prepare-drawport *selcorner*) (make-rect nil dp)) (10 (prepare-drawport *selcorner*) (make-rect t dp)) (11 (setq *current-draw-fun* (change-rop-menu))) (12 (prepare-drawport "(L or R) -- Top corner of SQUARE to rotate M -- Back to Menu") (rotate-window dp)) (13 (prepare-drawport *selcorner*) (move-area t dp)) (14 (prepare-drawport *selcorner*) (move-area nil dp)) (15 (setq *move-area-rop* (change-move-rop))) (16 (prepare-drawport "(L or R) -- Move Entering Cursor M -- Back to Menu") (enter-text dp)) (19 (prepare-drawport " ") (mirror nil dp)) (20 (prepare-drawport " ") (mirror t dp)) (21 (prepare-drawport "Give function to apply to viewport") (makewinlistener *userwindow*) (let ((maybe (read))) (if t (funcall (eval maybe) dp) (setwindowtitle (paintstruct-window *paintstuff*) "Unknown Function"))) (makewinlistener (paintstruct-window *paintstuff*))) (17 (prepare-drawport "(L or R) -- Select 64 x 64 area to edit M -- Back to Menu") (fat-bits dp)) (22 (jump-choose)) (23 (new-font dp)) (18 (when (confirm "Clear all these points (Yes or no)?") (blank))) (0 (vpputcharray dp fvp :rrpl rop-x rop-y " " (+ 12 (length msjump)) 0 (+ 11 (length msjump))) (vpputcharray dp fvp :rrpl rop-x (+ 15 rop-y) " " 15 0 14) (vpputcharray dp fvp :rrpl rop-x (+ 30 rop-y) " " 18 0 17) (return nil)) (-1 (cond ((confirm "Exit PAINT (and lose your image) (Yes or No)?") (vpputcharray dp fvp :rrpl rop-x rop-y " " (+ 12 (length msjump)) 0 (+ 11 (length msjump))) (vpputcharray dp fvp :rrpl rop-x (+ 15 rop-y) " " 15 0 14) (vpputcharray dp fvp :rrpl rop-x (+ 30 rop-y) " " 18 0 17) (destroy-all-vp) (return nil)) (t (makewinlistener (paintstruct-window *paintstuff*)))))))))) ; Make-win sets up the PAINT windows; this is only called ONCE per lisp! ; The window is saved when you get out of PAINT. ; (defun make-win () (let* ((wind (createwindow (getfullwindow *userwindow*) nil 0 0 nil (paintstruct-screen-x *paintstuff*) (paintstruct-screen-y *paintstuff*) t t "PerqPaint " "PAINT" t)) (vp (windowviewport wind))) (setf (paintstruct-window *paintstuff*) wind) (setf (paintstruct-drawport *paintstuff*) vp) ;actual drawing area (setf (paintstruct-off-view *paintstuff*) ;used for work space (makeviewport vp -32002 -32002 (paintstruct-pixels-x *paintstuff*) (paintstruct-pixels-y *paintstuff*) 0 t nil t)) (setf (paintstruct-off-whole *paintstuff*) ;used for work space (makeviewport vp -32002 -32002 (paintstruct-pixels-x *paintstuff*) (paintstruct-pixels-y *paintstuff*) 0 t nil t)) (setf (paintstruct-rot-view *paintstuff*) ;used for rotation (makeviewport vp -32002 -32002 512 512 0 t nil t)) (let ((big (make-array (* 64 64) :element-type '(mod 2))) (bot-patt (+ *patt-spacer* *top-patt*))) (show-pattern (patt1) big 3 *top-patt*) (show-pattern (bh) big 3 bot-patt) (show-pattern (half-tone) big *patt-spacer* *top-patt*) (show-pattern (patt2) big *patt-spacer* bot-patt) (show-pattern (patt3) big (* 2 *patt-spacer*) *top-patt*) (show-pattern (patt4) big (* 2 *patt-spacer*) bot-patt) (show-pattern (patt5) big (* 3 *patt-spacer*) *top-patt*) (show-pattern (patt6) big (* 3 *patt-spacer*) bot-patt) (show-pattern (patt7) big (* 4 *patt-spacer*) *top-patt*) (show-pattern (patt8 ) big (* 4 *patt-spacer*) bot-patt) (show-pattern (patt9 ) big (* 5 *patt-spacer*) *top-patt*) (show-pattern (patt10) big (* 5 *patt-spacer*) bot-patt) (show-pattern (patt11) big (* 6 *patt-spacer*) *top-patt*) (show-pattern (patt12) big (* 6 *patt-spacer*) bot-patt) (show-pattern (patt13) big (* 7 *patt-spacer*) *top-patt*) (show-pattern (patt14) big (* 7 *patt-spacer*) bot-patt) ; Draw current pattern (draw-current vp (* 6 *patt-spacer*) *top-patt* t)) ; ; Set up brush parameters ; (let* ((zedx (paintstruct-pixels-x *paintstuff*)) (zedy (paintstruct-pixels-y *paintstuff*)) (spacer 5) (*brushes-x1* (+ zedx 5))) (setq *brush-64y* (+ zedy spacer)) (setq *brush-32y* (+ zedy (* 2 spacer) 64)) (setq *brush-16y* (+ zedy (* 3 spacer) 96)) (setq *brush-8y* (+ zedy (* 4 spacer) 112)) (setq *brush-64x* *brushes-x1*) (setq *brush-32x* (+ *brushes-x1* 16)) (setq *brush-16x* (+ *brushes-x1* 24)) (setq *brush-8x* (+ *brushes-x1* 28))))) ; ; Put patterns and brushes up ; (defun init-screen (vp) ;draw patterns ;draw a borderline (vertical) (vpline vp :drawline (paintstruct-pixels-x *paintstuff*) 0 (paintstruct-pixels-x *paintstuff*) (paintstruct-screen-y *paintstuff*)) ;draw a borderline (horizontal) (vpline vp :drawline 0 (paintstruct-pixels-y *paintstuff*) (paintstruct-screen-x *paintstuff*) (paintstruct-pixels-y *paintstuff*)) ;draw a line to seperate menus from displayed RASTOP info (vpline vp :drawline (1+ (paintstruct-pixels-x *paintstuff*)) 660 (paintstruct-screen-x *paintstuff*) 660) ; put up brushes (show-brushes vp)) ;; ;; Top level call for PAINT ;; (export 'paint) (defun paint () (let ((v1 0) (v2 0) (v3 0) (v4 0)) (unwind-protect (progn (cond ((boundp '*paintstuff*) ;already made (restorewindow (paintstruct-window *paintstuff*)) ;bring it back (modifywindow (paintstruct-window *paintstuff*) 0 0 (paintstruct-screen-x *paintstuff*) (paintstruct-screen-y *paintstuff*) 0) (putviewportrectangle (paintstruct-drawport *paintstuff*) :RRPL 0 0 (paintstruct-pixels-x *paintstuff*) (paintstruct-screen-y *paintstuff*) (paintstruct-image *paintstuff*) (* (paintstruct-pixels-x *paintstuff*) (paintstruct-screen-y *paintstuff*)) 40 0 0)) (t ;fresh run of paint (setq *paintstuff* (make-paintstruct :font (getsysfont (windowviewport *userwindow*)) :pixels-x 592 :pixels-y 720 :screen-x (+ 592 175) :screen-y (+ 720 176) :grid-mod 1)) (setq *current-draw-fun* :drawline) (setq *move-area-rop* :rrpl) (setq *top-patt* (+ 4 (paintstruct-pixels-y *paintstuff*))) (make-win) ;default brushe sizes (setq *brush-w* 32) (setq *brush-h* 32) ; default brush (setq *brush-x* (+ 80 *brush-32x*) *brush-y* *brush-32y*))) (setwindowtitle (paintstruct-window *paintstuff*) "PerqPaint ... a new design in painting") (multiple-value-setq (v1 v2 v3 v4) (fullwindowstate *userwindow*)) (modifywindow *userwindow* 0 896 765 55 0) (setwindowtitle *userwindow* *blank-line*) (init-screen (paintstruct-drawport *paintstuff*)) (enablewinlistener (paintstruct-window *paintstuff*) accint:nullport (namestring (truename "lisp.keytran")) 0) (enableinput (paintstruct-drawport *paintstuff*) (namestring (truename "lisp.keytran")) 0) (setq *last-grid-x* 0 *last-grid-y* 0) (do-functions)) (unpaste-menu "OPTIONS:") (setwindowtitle *userwindow* (concatenate 'string (lisp-implementation-type) " " (lisp-implementation-version))) (when (boundp '*paintstuff*) (multiple-value-bind (available sap) (getviewportrectangle (paintstruct-drawport *paintstuff*) 0 0 (paintstruct-pixels-x *paintstuff*) (paintstruct-screen-y *paintstuff*) 0 0) (when (not available) (format t "WOOPS! Image not saved, sorry! ~%~%")) (setf (paintstruct-image *paintstuff*) (alien-sap sap))) (removewindow (paintstruct-window *paintstuff*))) (modifywindow *userwindow* v1 v2 v3 v4 0) (makewinlistener *userwindow*) ;return t t))) ;; ;; Low level; and other picture making stuff. ;; ;; 'paintpic.slisp' ;; ; ; Blanks the screen, paint viewport unless you specify otherwise. ; (defun blank (&optional (port (paintstruct-drawport *paintstuff*))) (vpcolorrect port :rectwhite 0 0 (paintstruct-pixels-x *paintstuff*) (paintstruct-pixels-y *paintstuff*))) ; ; for lines ; (defun make-line (dp) (loop (setwindowtitle (paintstruct-window *paintstuff*) "(L or R) -- Start Line M -- Drawing Menu ") (multiple-value-bind (a char c d) (get-points nil dp) (declare (ignore char)) (cond ((= a MIDDLEDOWN) (setq *last-grid-x* d *last-grid-y* c) (return nil)) ((left-or-right a) (setwindowtitle (paintstruct-window *paintstuff*) "(L or R) -- End Line M -- Abort Line") (let ((firstx d) (firsty c) (lastx d) (lasty c)) (vpline dp :xorline firstx firsty firstx firsty) (loop (multiple-value-bind (a char c d) (get-points t dp) (declare (ignore char)) (when (or (/= lastx d) (/= lasty c)) (vpline dp :xorline firstx firsty lastx lasty) (vpline dp :xorline firstx firsty d c) (setq lastx d lasty c)) (cond ((= a MIDDLEDOWN) (vpline dp :xorline firstx firsty d c) (return nil)) ((left-or-right a) (vpline dp :xorline firstx firsty d c) (vpline dp *current-draw-fun* firstx firsty d c) (return nil))))))))))) ; ; Freehand lets user draw 'pen' style ; (defun freehand (dp) (let ((fresh t) (prevx 0) (prevy 0)) (loop (setwindowtitle (paintstruct-window *paintstuff*) "(L or R) -- Turn On Drawing Mode M -- Back to Menu") (multiple-value-bind (a char c d) (get-points nil dp) (declare (ignore char)) (cond ((= a MIDDLEDOWN) (setq *last-grid-x* d *last-grid-y* c) (return nil)) ((left-or-right a) (setwindowtitle (paintstruct-window *paintstuff*) "M -- Turn Off Drawing Mode") (loop (multiple-value-bind (a char c d) (get-points t dp) (declare (ignore char)) (cond ((= a MIDDLEDOWN) (setq fresh t) (setq *last-grid-x* d *last-grid-y* c) (return nil)) (t (if fresh (vpline dp *current-draw-fun* d c d c) (vpline dp *current-draw-fun* prevx prevy d c)) (setq prevx d prevy c) (setq fresh nil)) (t (setq fresh t))))))))))) ; ; Make-rect lets the user make rectangles ; (defun make-rect (fill-p dp) ;filled rectangle or not? (loop (multiple-value-bind (xtop ytop wid hgt) (selectwindowregion (paintstruct-window *paintstuff*) dp) (when (null xtop) (return nil)) (cond (fill-p (vpcolorrect dp (case *current-draw-fun* (:drawline :rectblack) (:eraseline :rectwhite) (:xorline :rectinvert)) xtop ytop wid hgt)) (t (vpline dp *current-draw-fun* xtop ytop (+ -1 xtop wid) ytop) (vpline dp *current-draw-fun* xtop ytop xtop (+ -1 ytop hgt)) (vpline dp *current-draw-fun* xtop (+ -1 ytop hgt) (+ -1 xtop wid) (+ -1 ytop hgt)) (vpline dp *current-draw-fun* (+ -1 xtop wid) ytop (+ -1 xtop wid) (+ -1 ytop hgt)) (setq *last-grid-x* xtop *last-grid-y* ytop)))))) (defmacro sqr (num) `(* ,num ,num)) ; ; Make-circle lets the user make circles ; (defun make-circle (dp) (let ((rightmax (paintstruct-pixels-x *paintstuff*)) (bottmax (paintstruct-pixels-y *paintstuff*))) (loop (setwindowtitle (paintstruct-window *paintstuff*) "(L or R) -- Center of Circle M -- Back to Menu ") (multiple-value-bind (a char c d) (get-points nil dp) (declare (ignore char)) (cond ((= a MIDDLEDOWN) (setq *last-grid-x* d *last-grid-y* c) (return nil)) ((left-or-right a) (vpline dp :xorline d c d c) (setwindowtitle (paintstruct-window *paintstuff*) "(L or R) -- Radius M -- Abort Circle") (let ((firstx d) (firsty c)) (loop (multiple-value-bind (a char c d) (get-points t dp) (declare (ignore char)) (let ((rad (round (sqrt (+ (sqr (- d firstx)) (sqr (- c firsty))))))) (cond ((= a MIDDLEDOWN) (vpline dp :xorline firstx firsty firstx firsty) (return nil)) ((left-or-right a) (draw-circle firstx firsty rad (case *current-draw-fun* (:drawline :rectblack) (:eraseline :rectwhite) (:xorline :rectinvert)) dp) (vpline dp :xorline firstx firsty firstx firsty) (return nil)) (t (vpline dp :xorline (max 0 (- firstx rad )) firsty (min rightmax (+ firstx rad)) firsty) (vpline dp :xorline (max 0 (- firstx rad )) firsty (min rightmax (+ firstx rad)) firsty) (vpline dp :xorline firstx (max 0 (- firsty rad)) firstx (min bottmax (+ firsty rad))) (vpline dp :xorline firstx (max 0 (- firsty rad)) firstx (min bottmax (+ firsty rad)) ))))))))))))) ; ; Move-area is for moves and copies. If delete-p is true, then it is ; moving (i.e. delete what WAS there). ; (defun move-area (delete-p dp) (let ((win (paintstruct-window *paintstuff*)) (off (paintstruct-off-view *paintstuff*)) (whole (paintstruct-off-whole *paintstuff*)) (sizx (paintstruct-pixels-x *paintstuff*)) (sizy (paintstruct-pixels-y *paintstuff*))) (loop (multiple-value-bind (xtop ytop width height) (selectwindowregion win dp) (when (null xtop) (return)) (setcursorpos dp xtop ytop) (setwindowtitle win "(L or R) -- Select NEW Top Left M -- Drawing Menu") (vprop off :rrpl 0 0 width ;move area to move off screen height dp xtop ytop) (when delete-p ;blank region if moving (vpcolorrect dp :rectwhite xtop ytop width height)) (vprop whole :rrpl 0 0 ;move whole picture off screen sizx sizy dp 0 0) (let ((movex 0) (movey 0) (ab 0)) (loop (multiple-value-bind (a2 char c2 d2) (get-points t dp) (declare (ignore char)) (let* ((maxw (- sizx d2)) (maxh (- sizy c2)) (mov-w (min maxw width)) ;border checks (mov-h (min maxh height))) (cond ((or (left-or-right a2) (= a2 MIDDLEDOWN)) (multiple-value-setq (ab movex movey) (values a2 d2 c2)) (return)) (t (vprop dp :rrpl 0 0 sizx sizy whole 0 0) (vprop dp *move-area-rop* d2 c2 mov-w mov-h off 0 0)))))) (when (= ab MIDDLEDOWN) (setq *last-grid-x* movex *last-grid-y* movey) (return ab))))))) ;; ;; Uses view-put-ch-array to put characters on the screen from the keybaord ;; (defun enter-text (dp) (let* ((*paintfont* (paintstruct-font *paintstuff*))) (multiple-value-bind (ignore ignore ignore ignore wid hgt) (fontsize *paintfont*) (declare (ignore ignore)) (let ((maxright (- (paintstruct-pixels-x *paintstuff*) wid)) (maxbott (- (paintstruct-pixels-y *paintstuff*) 1))) (multiple-value-bind (a b dy dx) (get-points t dp) (declare (ignore a b)) (vpcolorrect dp :rectinvert dx (- dy hgt) wid hgt) (loop (multiple-value-bind (a b c d) (get-points t dp 0 hgt (- (paintstruct-pixels-x *paintstuff*) wid) (- (paintstruct-pixels-y *paintstuff*) 4)) (cond ((= a MIDDLEDOWN) (setq *last-grid-x* dx *last-grid-y* dy) (vpcolorrect dp :rectinvert dx (- dy hgt) wid hgt) (return nil)) ((left-or-right a) (vpcolorrect dp :rectinvert dx (- dy hgt) wid hgt) (setq dx d dy c) (vpcolorrect dp :rectinvert dx (- dy hgt) wid hgt)) ((= a 0) (let ((ch (string b))) (vpcolorrect dp :rectinvert dx (- dy hgt) wid hgt) (vpputcharray dp *paintfont* *move-area-rop* dx dy ch (length ch) 0 0) (setq dx (+ dx (fontstringwidthvector *paintfont* ch 1 1))) (when (>= dx maxright) (setq dx 0) (setq dy (+ dy hgt))) (when (>= dy maxbott) (setq dy hgt) (setq dx 0)) (vpcolorrect dp :rectinvert dx (- dy hgt) wid hgt))))))))))) ;; ;; ;; FAT BITS STUFF ;; ;; ; Draw-grid now does dots instead of lines. (defun draw-grid (strtx strty wid hgt siz &optional (port (paintstruct-drawport *paintstuff*))) (let ((*off-whole* (paintstruct-off-view *paintstuff*))) (blank *off-whole*) (dotimes (i (1+ wid)) (vpcolorrect *off-whole* :rectblack (* siz i) 0 1 1)) (dotimes (i (1+ hgt)) (vprop port :rrpl (* siz strtx) (* siz (+ i strty)) (* siz (1+ wid)) 1 *off-whole* 0 0)))) (defun fat-bits (dp) (let* ((win (paintstruct-window *paintstuff*)) (off (paintstruct-off-whole *paintstuff*)) (off2 (paintstruct-off-view *paintstuff*)) (maxx (paintstruct-pixels-x *paintstuff*)) (maxy (paintstruct-pixels-y *paintstuff*)) (bit-size 9) (move-size 64) (fat-size (* bit-size move-size)) (bot-size (- maxy fat-size)) (oldd -10000) (oldc -10000) (hold (paintstruct-grid-mod *paintstuff*)));horrible hack to save gridmod (setf (paintstruct-grid-mod *paintstuff*) 1) ; make grid mod 1 (loop (multiple-value-bind (a char c d) (get-points t dp 0 0 (- maxx move-size 1) (- maxy move-size 1)) (declare (ignore char)) (when (= a MIDDLEDOWN) (half-flash (1- oldd) (1- oldc) (+ oldd move-size) (+ oldc move-size) dp) (setf (paintstruct-grid-mod *paintstuff*) hold) ; set it back (return nil)) (when (or (/= d oldd) (/= c oldc)) (half-flash (1- oldd) (1- oldc) (+ oldd move-size) (+ oldc move-size) dp) (setq oldd d oldc c) (half-flash (1- d) (1- c) (+ d move-size) (+ c move-size) dp)) (when (left-or-right a) ;save where cursor is (setq *last-grid-x* d *last-grid-y* c) (setwindowtitle win "L -- White M -- Select New Region R -- Black") ;store picture (vprop off :rrpl 0 0 maxx maxy dp 0 0) ;box area (half-flash (1- d) (1- c) (+ move-size d) (+ move-size c) dp) (let* ((origx d) (origy c) (coffs (min (- maxy bot-size) (max 0 (- c (floor bot-size 2))))) (newy (+ fat-size (- c coffs)))) ;put area at bottom (vprop dp :rrpl 0 fat-size maxx bot-size dp 0 coffs) ;clear top part (vpcolorrect dp :rectwhite 0 0 maxx fat-size) ;put bits up (magnify bit-size move-size 0 0 origx newy dp off2) (draw-grid 0 0 (1- move-size) (1- move-size) bit-size) (vpline dp :drawline 0 fat-size (- fat-size bit-size) fat-size) (vpline dp :drawline (- fat-size bit-size) 0 (- fat-size bit-size) fat-size) (setcursorpos dp 100 100) (loop (multiple-value-bind (a char c d) (get-points nil dp 0 0 (- fat-size bit-size) fat-size) (declare (ignore char)) (when (= a MIDDLEDOWN) (setcursorpos dp *last-grid-x* *last-grid-y*) (setwindowtitle win "(L or R) -- Select 64 x 64 area to edit M -- Back to Menu") (return nil)) (when (left-or-right a) (let ((point (if (= a LEFTDOWN) :rectwhite :rectblack))) (vpcolorrect dp point (1+ (constrain d bit-size)) (1+ (constrain c bit-size)) (- bit-size 2) (- bit-size 2)) (vpcolorrect dp point (+ origx (floor d bit-size)) (+ newy (floor c bit-size)) 1 1))))) ;put back picture (vprop off :rrpl 0 (1+ coffs) maxx (1- bot-size) dp 0 (1+ fat-size)) (vprop dp :rrpl 0 0 maxx maxy off 0 0) (half-flash (1- origx) (1- origy) (+ move-size origx) (+ move-size origy) dp))))))) (defun magnify (size move-size newx newy x y port temp) (blank temp) (dotimes (i move-size) (vprop temp :rrpl (1+ (* size i)) 0 1 move-size port (+ i x) y)) (dotimes (i (- size 3)) (vprop temp :ror (1+ i) 0 (* move-size size) move-size temp i 0)) (dotimes (i move-size) (vprop port :rrpl newx (+ 1 newy (* size i)) (* (1- move-size) size) 1 temp newx (+ i newy))) (dotimes (i (- size 3)) (vprop port :ror newx (+ newy 1 i) (* (1- move-size) size) (* (1- move-size) size) port newx (+ newy i)))) ;; Mirroring and rotation ; ; ; Mirror flips an image about the vertical or horizontal axis (defun mirror (v-or-h dp) ;nil=v t=h (let ((off (paintstruct-off-view *paintstuff*))) (blank off) (loop (multiple-value-bind (xtop ytop wid hgt) (selectwindowregion (paintstruct-window *paintstuff*) dp) (when (null xtop) (return nil)) (cond (v-or-h (dotimes (i hgt) (vprop off :rrpl 0 (- hgt i) wid 1 dp (1+ xtop) (+ -1 i ytop))) (vprop dp *move-area-rop* xtop ytop wid hgt off 0 1)) (t (dotimes (i wid) (vprop off :rrpl (- wid i) 0 1 hgt dp (+ -1 i xtop) (1+ ytop))) (vprop dp *move-area-rop* xtop ytop wid hgt off 1 0))))))) ; ; Rotate-window gets a region and does a 90 degree flip (counterclockwise). ; (defun rotate-window (dp) (let ((win (paintstruct-window *paintstuff*)) (sizx (paintstruct-pixels-x *paintstuff*)) (sizy (paintstruct-pixels-y *paintstuff*))) (loop (setwindowtitle win "(L or R) - Top corner of SQUARE to rotate M -- Back to Menu") (multiple-value-bind (a char ytop xtop ) (get-points nil dp) (declare (ignore char)) (when (= a MIDDLEDOWN) (return nil)) (when (left-or-right a) (setwindowtitle win "(L or R) - Bottom of SQUARE to rotate M -- Abort Square") (loop (multiple-value-bind (a char ybot xbot) (get-points t dp) (declare (ignore char)) (cond ((< xbot xtop) (setq xbot xtop)) ((< ybot ytop) (setq ybot ytop))) (let* ((maxw (- sizx xtop)) (maxh (- sizy ytop)) (wid (- xbot xtop)) (hgt (- ybot ytop)) (sq (min 512 (min maxh maxw (max wid hgt)))) ;max siz 512x512 (botx (+ xtop sq)) (boty (+ ytop sq))) (flash-area xtop ytop botx boty dp) (when (= a MIDDLEDOWN) (return nil)) (when (left-or-right a) (rotate-wind xtop ytop sq) (return nil)))))))))) (defmacro copy-all-to (from xoff yoff to func) `(vprop ,to ,func ,xoff ,yoff (- size-of ,xoff) (- size-of ,yoff) ,from 0 0)) (defmacro copy-all-from (to xoff yoff from func) `(vprop ,to ,func 0 0 (- size-of ,xoff) (- size-of ,yoff) ,from ,xoff ,yoff)) (defun next-2-power (number) (do ((pow 1 (* 2 pow))) ((<= number pow) pow))) (defun rotate-wind (x y width) (let* ((dp (paintstruct-drawport *paintstuff*)) (mask (paintstruct-off-view *paintstuff*)) (temp (paintstruct-off-whole *paintstuff*)) (rot-port (paintstruct-rot-view *paintstuff*)) (size-of (next-2-power width))) (blank mask) (blank temp) ;clear the offscreen viewports (vpcolorrect mask :rrpl 0 0 (/ size-of 2) (/ size-of 2)) ;make the first mask ;move picture to temp ;temp will be worked on; dp will be ;for storage (vprop temp :rrpl 0 0 width width dp x y) (do ((part (floor size-of 2) (floor part 2))) ((< part (paintstruct-grid-mod *paintstuff*))) (copy-all-to mask 0 0 rot-port :rrpl) ;0 (copy-all-to mask 0 part rot-port :ror) ;4 (copy-all-to temp 0 0 rot-port :rand) ;2 (copy-all-to rot-port 0 0 temp :rxor) ;6 (copy-all-from rot-port part 0 temp :rxor) ;6 (copy-all-from temp part 0 temp :ror) ;4 (copy-all-to rot-port part 0 temp :rxor) ;6 (copy-all-to temp 0 0 rot-port :rrpl) ;0 (copy-all-from rot-port part part temp :rxor) ;6 (copy-all-to mask 0 0 rot-port :rand) ;2 (copy-all-to rot-port 0 0 temp :rxor) ;6 (copy-all-to rot-port part part temp :rxor) ;6 (copy-all-from mask (floor part 2) (floor part 2) mask :rand) ;2 (copy-all-to mask part 0 mask :ror) ;4 (copy-all-to mask 0 part mask :ror) ;4 (vprop dp :rrpl x y width width temp (- size-of width) 0)))) ;put the picture back ;;; Circle drawing stuff. ;;; Written by Skef Wholey. ;;; ;;; Draw-Circle is actually slower than calling Draw-Filled-In-Circle twice, ;;; so you might not want to use it at all. ; ; but: calling draw-circle twice whites out the center of the circle; ; not necessarily desirable! ; (defmacro draw-point (vp function x y) `(when (and (< ,x maxr) (< ,y maxl)) (vpcolorrect ,vp ,function ,x ,y 1 1))) (defun draw-circle (center-x center-y radius &optional (function :rectblack) (vp (sapphuser:windowviewport *userwindow*))) (do ((y 0) (f 0) (x radius) (maxr (paintstruct-pixels-x *paintstuff*)) (maxl (paintstruct-pixels-y *paintstuff*))) (()) (draw-point vp function (+ center-x x) (- center-y y)) (draw-point vp function (- center-x x) (+ center-y y)) (draw-point vp function (+ center-x y) (+ center-y x)) (draw-point vp function (- center-x y) (- center-y x)) (setq f (+ f y y 1) y (1+ y)) (if (>= f x) (setq f (- f x x -1) x (- x 1))) (if (> y x) (return nil)) (draw-point vp function (+ center-x x) (+ center-y y)) (draw-point vp function (- center-x x) (- center-y y)) (draw-point vp function (+ center-x y) (- center-y x)) (draw-point vp function (- center-x y) (+ center-y x)) (if (= y x) (return nil)))) (defmacro draw-horizontal-line (vp function x y width) `(vpcolorrect ,vp ,function ,x ,y ,width 1 )) (defun draw-filled-in-circle (center-x center-y radius &optional (function :rectblack) (vp (sapphuser:windowviewport *userwindow*))) (do ((y 0) (f 0) (x radius) (last-top-x 0) (last-bottom-x 0)) (()) (draw-horizontal-line vp function (- center-x x) (+ center-y y) (+ x x)) (when (/= x last-top-x) (draw-horizontal-line vp function (- center-x y) (- center-y x) (+ y y)) (setq last-top-x x)) (setq f (+ f y y 1) y (1+ y)) (if (>= f x) (setq f (- f x x -1) x (- x 1))) (if (> y x) (return nil)) (draw-horizontal-line vp function (- center-x x) (- center-y y) (+ x x)) (when (/= x last-bottom-x) (draw-horizontal-line vp function (- center-x y) (+ center-y x) (+ y y)) (setq last-bottom-x x)) (if (= y x) (return nil)))) ;; ;; The painting with patterns stuff for PAINT ;; ; ; 'paintpatt.slisp' ; ; Here are 14 patterns to start the user off with: ; (defun patt1 () (make-array (* 8 8) :element-type '(mod 2) :initial-contents '(1 1 1 1 1 0 0 0 0 1 1 1 0 1 0 0 0 0 1 0 0 0 1 0 0 1 0 0 0 1 1 1 1 0 0 0 1 1 1 1 0 0 0 1 0 1 1 1 0 0 1 0 0 0 1 0 0 1 1 1 0 0 0 1))) (defun patt2 () (make-array (* 8 8) :element-type '(mod 2) :initial-contents '(0 0 0 0 1 0 0 0 0 0 0 1 1 1 0 0 0 0 1 0 0 0 1 0 1 1 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0))) (defun patt3 () (make-array (* 8 8) :element-type '(mod 2) :initial-contents '(0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1))) (defun patt4 () (make-array (* 8 8) :element-type '(mod 2) :initial-contents '(1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0))) (defun patt5 () (make-array (* 8 8) :element-type '(mod 2) :initial-contents '(1 1 1 0 1 1 1 0 1 1 0 1 1 1 0 1 1 0 1 1 1 0 1 1 0 1 1 1 0 1 1 1 1 1 1 0 1 1 1 0 1 1 0 1 1 1 0 1 1 0 1 1 1 0 1 1 0 1 1 1 0 1 1 1))) (defun patt6 () (make-array (* 8 8) :element-type '(mod 2) :initial-contents '(0 0 0 1 0 0 0 1 0 0 1 0 0 0 1 0 0 1 0 0 0 1 0 0 1 0 0 0 1 0 0 0 0 0 0 1 0 0 0 1 0 0 1 0 0 0 1 0 0 1 0 0 0 1 0 0 1 0 0 0 1 0 0 0))) (defun patt7 () (make-array (* 8 8) :element-type '(mod 2) :initial-contents '(0 1 1 1 0 1 1 1 1 0 1 1 1 0 1 1 1 1 0 1 1 1 0 1 1 1 1 0 1 1 1 0 0 1 1 1 0 1 1 1 1 0 1 1 1 0 1 1 1 1 0 1 1 1 0 1 1 1 1 0 1 1 1 0))) (defun patt8 () (make-array (* 8 8) :element-type '(mod 2) :initial-contents '(1 0 0 0 1 0 0 0 0 1 0 0 0 1 0 0 0 0 1 0 0 0 1 0 0 0 0 1 0 0 0 1 1 0 0 0 1 0 0 0 0 1 0 0 0 1 0 0 0 0 1 0 0 0 1 0 0 0 0 1 0 0 0 1))) (defun patt9 () (make-array (* 8 8) :element-type '(mod 2) :initial-contents '(1 1 1 1 1 1 1 0 1 1 1 1 1 1 0 1 1 1 1 1 1 0 1 1 1 1 1 1 0 1 1 1 1 1 1 0 1 1 1 1 1 1 0 1 1 1 1 1 1 0 1 1 1 1 1 1 0 1 1 1 1 1 1 1))) (defun patt10 () (make-array (* 8 8) :element-type '(mod 2) :initial-contents '(0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0))) (defun patt11 () (make-array (* 8 8) :element-type '(mod 2) :initial-contents '(0 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 0))) (defun patt12 () (make-array (* 8 8) :element-type '(mod 2) :initial-contents '(1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1))) ;; ;; here are some extra patterns (defun brick () (make-array (* 8 8) :element-type '(mod 2) :initial-contents '(1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0))) (defun half-tone () (make-array (* 8 8) :element-type '(mod 2) :initial-contents '(1 0 1 0 1 0 1 0 0 1 0 1 0 1 0 1 1 0 1 0 1 0 1 0 0 1 0 1 0 1 0 1 1 0 1 0 1 0 1 0 0 1 0 1 0 1 0 1 1 0 1 0 1 0 1 0 0 1 0 1 0 1 0 1))) (defun bh () (make-array (* 8 8) :element-type '(mod 2) :initial-contents '(0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 1 0 1 1 0 0 0 0 0 1 1 1 0 0 0 0 0 0 1 1 0 0 0 0 0 0 1 1 0 0 0 0 0 1 1 1 1 0 0 0 0 0 0 0 0 0 0))) (defun patt13 () (make-array (* 8 8) :element-type '(mod 2) :initial-element 1)) (defun patt14 () (make-array (* 8 8) :element-type '(mod 2) :initial-element 0)) (defun move-pattern (sa da xd yd) (dotimes (i 8) (dotimes (j 8) (setf (bit da (+ (+ i xd) (* 64 (+ j yd)))) (bit sa (+ i (* 8 j))))))) (defun show-pattern (aray big x y) (let ((vp (paintstruct-drawport *paintstuff*))) (dotimes (i 8) (dotimes (j 8) (move-pattern aray big (* i 8) (* j 8)))) (vpcolorrect vp :rectblack (1- x) (1- y) 66 66) (vpcolorrect vp :rectwhite x y 64 64) (putviewportrectangle vp :RRPL x y 64 64 big (* 64 64) 4 0 0))) (defun draw-current (dp x y first-call-p) (progn (unless first-call-p ; unhighlight old pattern (vpcolorrect dp :rectinvert (- *pattern-x* 4) (- *pattern-y* 4) 72 72) (vpcolorrect dp :rectinvert *pattern-x* *pattern-y* 64 64)) ; highlight new pattern (vpcolorrect dp :rectinvert (- x 4) (- y 4) 72 72) (vpcolorrect dp :rectinvert x y 64 64) (setq *pattern-x* x) (setq *pattern-y* y))) (defun select-default (dp) (setcursorpos dp *pattern-x* *pattern-y*) (let ((hold (paintstruct-grid-mod *paintstuff*)));horrible hack to save gridmod (setf (paintstruct-grid-mod *paintstuff*) 1) ; make grid mod 1 (loop (multiple-value-bind (a char c d) (get-points nil dp 0 (paintstruct-pixels-y *paintstuff*) (paintstruct-pixels-x *paintstuff*) (paintstruct-screen-y *paintstuff*)) (declare (ignore a char)) (cond ((= a MIDDLEDOWN) (setf (paintstruct-grid-mod *paintstuff*) hold) ;restore grid mod ;set up offscreen area (return nil)) ((and (> c (paintstruct-pixels-y *paintstuff*)) (< d (paintstruct-pixels-x *paintstuff*))) (let ((y (if (< c (+ *patt-spacer* *top-patt*)) *top-patt* (+ *patt-spacer* *top-patt*))) (x (max 3 (* *patt-spacer* (floor d *patt-spacer*))))) (draw-current dp x y nil)))))))) ; ; Picture stuff for PAINT ; (defun painting (dp) (let ((off (paintstruct-off-view *paintstuff*))) ;set up offscreen area; must be done here because we use off-view for other stuff (vprop off :RRPL 0 0 64 64 dp *pattern-x* *pattern-y*) (vprop off :RRPL 0 64 64 64 dp *pattern-x* *pattern-y*) (vprop off :RRPL 64 0 64 64 dp *pattern-x* *pattern-y*) (vprop off :RRPL 64 64 64 64 dp *pattern-x* *pattern-y*) (loop (multiple-value-bind (a char c d) (get-points t dp) (declare (ignore char)) (cond ((= a MIDDLEDOWN) (setq *last-grid-x* d *last-grid-y* c) (return nil)) ((left-or-right a) (setwindowtitle (paintstruct-window *paintstuff*) "M -- Turn Off Painting Mode") (loop (multiple-value-bind (a char c d) (get-points t dp) (declare (ignore char)) (cond ((= a MIDDLEDOWN) (setwindowtitle (paintstruct-window *paintstuff*) "(L or R) Turn On Painting Mode M -- Back to Menu") (return nil)) (t (let ((width (min *brush-w* (- (paintstruct-pixels-x *paintstuff*) d 1))) (height (min *brush-h* (- (paintstruct-pixels-y *paintstuff*) c 1)))) (when (< c (1- (paintstruct-pixels-y *paintstuff*))) ; ; ; If you don't mind the extra slowness, ; the next two lines show where ; the brush is on the screen. ; ;(vprop dp :rxor d c width height dp *brush-x* *brush-y*) ;(vprop dp :rxor d c width height dp *brush-x* *brush-y*) ; First cut a 'hole' in screen if replacing, replace-noting (when (or (eq *move-area-rop* :RRPL) (eq *move-area-rop* :RNOT)) (vprop dp :RANDNOT d c width height dp *brush-x* *brush-y*)) ; Put the pattern (or it's inverse) offscreen (if (or (eq *move-area-rop* :RRPL) (eq *move-area-rop* :RAND) (eq *move-area-rop* :ROR) (eq *move-area-rop* :RXOR)) (vprop off :RRPL 0 130 width height off (mod d 64) (mod c 64)) (vprop off :RNOT 0 130 width height off (mod d 64) (mod c 64))) ; Cut out a border around the offscreen pattern; like the brush (vprop off :RAND 0 130 width height dp *brush-x* *brush-y*) ;for anding, put a black area around pattern; since "1 AND x=x" (when (or (eq *move-area-rop* :RAND) (eq *move-area-rop* :RANDNOT)) (vpcolorrect off :rectblack 0 195 64 64) (vprop off :RANDNOT 0 195 width height dp *brush-x* *brush-y*) (vprop off :ROR 0 130 width height off 0 195)) ; The final step; put it back together (when (or (eq *move-area-rop* :RRPL) (eq *move-area-rop* :RNOT) (eq *move-area-rop* :ROR) (eq *move-area-rop* :RORNOT)) (vprop dp :ROR d c width height off 0 130)) (when (or (eq *move-area-rop* :RXOR) (eq *move-area-rop* :RXOR)) (vprop dp :RXOR d c width height off 0 130)) (when (or (eq *move-area-rop* :RAND) (eq *move-area-rop* :RANDNOT)) (vprop dp :RAND d c width height off 0 130)))))))))))))) (defun show-brushes (dp) ;four square brushes: (vpcolorrect dp :rectblack *brush-64x* *brush-64y* 64 64) (vpcolorrect dp :rectblack *brush-32x* *brush-32y* 32 32) (vpcolorrect dp :rectblack *brush-16x* *brush-16y* 16 16) (vpcolorrect dp :rectblack *brush-8x* *brush-8y* 8 8) ;four round brushes (draw-filled-in-circle (+ 80 *brush-64x* 32) (+ *brush-64y* 32) 32 :rectblack dp) (draw-filled-in-circle (+ 80 *brush-32x* 16) (+ *brush-32y* 16) 16 :rectblack dp) (draw-filled-in-circle (+ 80 *brush-16x* 8) (+ *brush-16y* 8) 8 :rectblack dp) (draw-filled-in-circle (+ 80 *brush-8x* 4) (+ *brush-8y* 4) 4 :rectblack dp) ; Highlight brush (vpcolorrect dp :rectinvert (- *brush-x* 3) (- *brush-y* 3) (+ *brush-w* 6) (+ *brush-h* 6)) (vpcolorrect dp :rectinvert (1- *brush-x*) (1- *brush-y*) (+ 2 *brush-w*) (+ 2 *brush-h*))) (defun select-brush (dp) (let ((topx (paintstruct-pixels-x *paintstuff*)) (topy (paintstruct-pixels-y *paintstuff*)) (botx (paintstruct-screen-x *paintstuff*)) (boty (paintstruct-screen-y *paintstuff*)) (hold (paintstruct-grid-mod *paintstuff*))) (setf (paintstruct-grid-mod *paintstuff*) 1) (setcursorpos (paintstruct-drawport *paintstuff*) (+ topx 5) (+ *brush-y* 5)) (loop (multiple-value-bind (a char c d) (get-points nil dp topx topy botx boty) (declare (ignore char)) (cond ((= a MIDDLEDOWN) (setf (paintstruct-grid-mod *paintstuff*) hold) (return nil)) (t ;erase old lines (vpcolorrect dp :rectinvert (- *brush-x* 3) (- *brush-y* 3) (+ *brush-w* 6) (+ *brush-h* 6)) (vpcolorrect dp :rectinvert (1- *brush-x*) (1- *brush-y*) (+ *brush-w* 2) (+ *brush-h* 2)) (cond ((< c *brush-32y*) (setq *brush-h* 64 *brush-w* 64 *brush-x* *brush-64x* *brush-y* *brush-64y*)) ((< c *brush-16y*) (setq *brush-h* 32 *brush-w* 32 *brush-x* *brush-32x* *brush-y* *brush-32y*)) ((< c *brush-8y*) (setq *brush-h* 16 *brush-w* 16 *brush-x* *brush-16x* *brush-y* *brush-16y*)) (t (setq *brush-h* 8 *brush-w* 8 *brush-x* *brush-8x* *brush-y* *brush-8y*))) (if (> d (+ 80 *brush-64x*)) (setq *brush-x* (+ 80 *brush-x*))) ;show new brush (vpcolorrect dp :rectinvert (- *brush-x* 3) (- *brush-y* 3) (+ *brush-w* 6) (+ *brush-h* 6)) (vpcolorrect dp :rectinvert (1- *brush-x*) (1- *brush-y*) (+ *brush-w* 2) (+ *brush-h* 2)))))))) ; ; Menu stuff for PAINT ; ; 'paintmenu.slisp' ; (defun put-up-menu () (menu-choose :items (("Load Screen" :value 1 :help "Select file PAINT picture is stored in.") ("Save Screen" :value 2 :help "Select file to store picture PAINT in.") ("Load Bitmap" :value 24 :help "Load any type of bitmap") ("Save Bitmap" :value 25 :help "Select area to store.") ("Make Pressfile" :value 26 :help "Send screen to pressfile for dover") (" " :no-select) ("Paint" :value 3 :help "Paint with brush.") ("Change Brush " :value 4 :help "Select new brush to paint with.") ("Change Pattern" :value 5 :help "Select new pattern to paint with.") (" " :no-select) ("Draw Freehand" :value 6 :help "Move a pen and draw.") ("Draw Line" :value 7 :help "Connect two dots together.") ("Draw Circle" :value 8 :help "Choose center and radius.") ("Lined Rectgle" :value 9 :help "Choose opposite corners; connects with lines.") ("Solid Rectgle" :value 10 :help "Choose opposite corners; region filled in.") (" " :no-select) ("Move Area" :value 13 :help "Mark an area, then move it. Original goes away.") ("Copy Area" :value 14 :help "Mark an area; then move it. Original is unchanged") ("Characters" :value 16 :help "Enter characters from keyboard.") ("Char Font" :value 23 :help "Select a new KST font for characters.") ("Rotate Area" :value 12 :help "Rotate an area clockwise by 90 degrees.") ("Mirror Vert" :value 19 :help "Mirror a region vertically") ("Mirror Horz" :value 20 :help "Mirror a region horizontally") (" " :no-select) ("Pick TRI ROP" :value 11 :help "Select RastOP for anything that draws, erases, or inverts.") ("Pick OCTO ROP" :value 15 :help "Pick the RastOP for anything that can do all eight possible raster ops.") (" " :no-select) ("Clear Screen" :value 18 :help "Clear entire screen.") ("Fat Bits" :value 17 :help "Point edit a 64X64 area.") ("Mouse Jump" :value 22 :help "Make mouse jump mod ") ("Apply" :value 21 :help "Apply a function to the viewport") (" " :no-select) ("LISP" :value 0 :help "Go back to lisp; everything saved.") ("Exit Paint" :value -1 :help "Leave PAINT and DESTROY all information, and viewports.")) :position-x *menu-pos-x* :position-y 0 :title "OPTIONS:" :in-window (paintstruct-window *paintstuff*) :default-item "Paint" :paste-up :and-choose )) (defun change-rop-menu () (menu-choose :items (("White " :value :eraseline :help "White lines, circles, regions.") ("Black " :value :drawline :help "Black lines, circles, regions.") ("Invert" :value :xorline :help "Inverse lines, circles, regions.")) :position-x *menu-pos-x* :position-y *menu-other-pos-y* :in-window (paintstruct-window *paintstuff*) :title "Draw Rastop:")) (defun change-move-rop () (menu-choose :items (("Repl" :value :rrpl :help "Replace current area with move area.")  ("Not" :value :rnot :help "Replace current area with invert of move area.") ("And" :value :rand :help "Replace current area with AND of current area and move area") ("And Not" :value :randnot :help "Replace current area with AND of current area and invert of move area") ("Or" :value :ror :help "Replace current area with OR of current area and move area") ("Or Not" :value :rornot :help "Replace current area with OR of current area and invert of move area") ("XOr" :value :rxor :help "Replace current area with XOR of current area and move area") ("XNor" :value :rxnor :help "Replace current area with XOR of current area and invert of move area")) :position-x *menu-pos-x* :position-y *menu-other-pos-y* :title "Mov/Char ROP:" :default-item "Repl" :in-window (paintstruct-window *paintstuff*))) (format t "Paint loaded. To execute, type: (paint:paint) ~%")