#| -*- Mode:LISP; Base: 10; Package:(VISTA-LIBRARY :use (LISP)); Syntax: Common-lisp; Readtable: CL -*- |# ;;; Copyright (C) LISP Machine, Inc. 1984, 1985, 1986 ;;; See filename "Copyright" for ;;; licensing and release information. ;;; ******************************************* ;;; ***** PROPRIETARY AND CONFIDENTIAL!!! ***** ;;; ******************************************* (in-package 'vista-library :use '(lisp)) ;;;; Other stuff ;;; This is the part of the vista library that ;;; is device independent. ;;; including some macros and data structures (export '(MAKE-SEGMENT SEGMENT-DEVICE WITH-TRANSFORM POINT LINE LINE-RELATIVE MOVE MOVE-RELATIVE ORTHO MAKE-POLYGON MAKE-VIEWPORT VIEWPORT-LEFT VIEWPORT-RIGHT VIEWPORT-BOTTOM VIEWPORT-TOP MAKE-ENVIRONMENT %SET-ENVIRONMENT make-2d-environment make-3d-environment make-perspective-environment %MOUSE-ENVIRONMENT-SHAPE DEFDEMO DEMO DRAWING WITH-VISTA-MOUSE SHADE-COLORS FROB-COLORS VIEWPORT-ASPECT-RATIO READ-POINT)) ;;; Changes ;;; 4/16/86 EFH put (:constructor nil) in segment defstruct ;;; 5/05/86 PECANN macro DRAWING ;;; 5/14/86 PECANN struct mouse-click ;;; 5/15/86 PECANN macro WITH-VISTA-MOUSE ;;; 5/16/86 EFH added exit to demo ;;; 5/28/86 PECANN extra point in relative polygons (for closing) ;;; 6/06/86 EFH added VIEWPORT and ENVIRONMENT objects ;;; 6/11/86 PECANN removed %set-viewport ;;; 6/07/86 PW,RPK fixed (drawing ...) so that it works in a general way ;;; 6/07/86 PW steal-mouse -> mouse in drawing and %mouse-environment-shape ;;; 8/22/86 PECANN used #+/- to keep non-lispms from seeing fonts:... ;;; 9/06/86 PECANN added function viewport-aspect-ratio ;;; 9/09/86 PECANN added nargs macro READ-POINT ;;; 9/13/86 PECANN ? -> -p ;;; 9/14/86 PECANN -p -> p ;;; 9/17/86 PECANN added message to frob-colors (defmacro WITH-VISTA-MOUSE (&body body) `(unwind-protect (progn (mouse t) ,@body) (mouse nil))) (defstruct (mouse-click (:conc-name mouse-click-) (:predicate nil)) buttons x y) (defmacro DRAWING (&body body) "Allow device to prevent mouse or cursor interference, etc." `(call-with-locked-device #'(lambda () #+(or lmi symbolics) (declare (sys:downward-function)) ,@body))) ; `(zl:with-lock (*iris-lock*) ; (if (typep *current-display-device* 'iris) (wait-for-iris)) ; (let ((cv (get-cursor-visibility))) ; (unwind-protect ; (progn ; (when cv (set-cursor-visibility nil)) ; ,@body) ; (when cv (set-cursor-visibility t)))))) ;;; Does this need an unwind protect? (defmacro MAKE-SEGMENT (keywords &body body) "Returns a segment containing the graphics commands executed in the body" `(unwind-protect (prog1 (open-segment ,@keywords) ,@body) (close-segment))) (defmacro WITH-TRANSFORM (&body body) `(unwind-protect (progn (push-transform) ,@body) (pop-transform))) ;;; WITH-POSITION ;; This doesn't work?? ;(defmacro POINT (x y &optional ((z zp))) ; (if zp ; `(POINT3 ,x ,y ,z) ; `(POINT2 ,x ,y))) (defun nargs-macro-nargs-error (n nargses) (error "Wrong number of args to a macro: ~d passed, ~a required." n nargses)) (eval-when (eval compile load) (defun nargses (clauses) (let ((nargses ()) n) (dolist (c clauses) (setq n (car c)) (cond ((numberp n) (push n nargses)) ((listp n) (setq nargses (append n nargses))) (t (error "Malconstructed case in nargs macro: ~a" n)))) (nreverse nargses))) ) (defmacro def-nargs-macro (name lambda-list &body clauses) `(defmacro ,name (&rest args) #+lispm (declare (zl:arglist . ,lambda-list)) ,(if (stringp (car clauses)) (pop clauses)) `(,(case (length args) ,@clauses (T (nargs-macro-nargs-error (length args) ',(nargses clauses)))) ,@args))) (defmacro def-2d-or-3d-macro (name lambda-list doc-string 2d-op 3d-op) `(def-nargs-macro ,name ,lambda-list ,doc-string (2 ',2d-op) (3 ',3d-op))) (def-2d-or-3d-macro POINT (x y &optional z) "Draws a point at the specified position." POINT2 POINT3) (def-2d-or-3d-macro LINE (x y &optional z) "Draws a line from the current graphics position to the specified position." LINE2 LINE3) (def-2d-or-3d-macro LINE-RELATIVE (dx dy &optional dz) "Draws a line from the current graphics position to the position (dx, dy, dz) away." LINE-RELATIVE2 LINE-RELATIVE3) (def-2d-or-3d-macro MOVE (x y &optional z) "Sets the current graphics position." MOVE2 MOVE3) (def-2d-or-3d-macro MOVE-RELATIVE (x y &optional z) "Sets the current graphics position." MOVE-RELATIVE2 MOVE-RELATIVE3) (def-2d-or-3d-macro READ-POINT (x y &optional z) "Returns the color of the pixel corresponding to a point on the screen" READ-POINT2 READ-POINT3) (def-nargs-macro ORTHO (left right bottom top &optional near far) "Set the current transform to specify an orthographic projection" (4 'ORTHO2) (6 'ORTHO3)) ;---------------------------------------------------------------- ;;;; Segments (defstruct (SEGMENT (:constructor nil) (:print-function print-segment)) (device *current-display-device*) translatablep x-rotatablep y-rotatablep z-rotatablep scalablep colorablep) (defun print-segment (seg stream depth) (format stream "#<~a ~a>" (type-of seg) #+lispm (zl:%pointer seg) #-lispm "")) ;---------------------------------------------------------------- ;;;; Polygons (defstruct (POLYGON (:conc-name poly-) (:constructor %make-polygon)) type (number-of-points 0 :type integer) (integerp t) points) (defun MAKE-POLYGON (type &rest coords) (let* ((2dp (member type '(:2d :2d-relative) :test #'eq)) (relativep (member type '(:2d-relative :3d-relative) :test #'eq)) (integerp (every #'(lambda (c) (typep c 'integer)) coords)) (d (if 2dp 2 3)) (n-points (/ (length coords) d)) (point-array (make-array (list (+ n-points (if relativep 1 0)) d) :element-type t)) ;(if integerp 'integer t)))) (sum-x 0) (sum-y 0) (sum-z 0)) (cond (2dp (dotimes (i n-points) (incf sum-x (setf (aref point-array i 0) (car coords))) (incf sum-y (setf (aref point-array i 1) (cadr coords))) (setq coords (cddr coords))) (when relativep (setf (aref point-array n-points 0) (- sum-x)) (setf (aref point-array n-points 1) (- sum-y)))) (t (dotimes (i n-points) (incf sum-x (setf (aref point-array i 0) (car coords))) (incf sum-y (setf (aref point-array i 1) (cadr coords))) (incf sum-z (setf (aref point-array i 2) (caddr coords))) (setq coords (cdddr coords))) (when relativep (setf (aref point-array n-points 0) (- sum-x)) (setf (aref point-array n-points 1) (- sum-y)) (setf (aref point-array n-points 2) (- sum-z))))) (%make-polygon :number-of-points (+ n-points (if relativep 1 0)) :type type :integerp integerp :points point-array))) (defmacro POLY-POINT-X (poly point-index) `(aref (poly-points ,poly) ,point-index 0)) (defun SET-POLY-POINT-X (poly point-index new-x) (unless (typep new-x 'integer) (setf (poly-integerp poly) nil)) (setf (poly-point-x poly point-index) new-x)) (defmacro POLY-POINT-Y (poly point-index) `(aref (poly-points ,poly) ,point-index 1)) (defun SET-POLY-POINT-Y (poly point-index new-y) (unless (typep new-y 'integer) (setf (poly-integerp poly) nil)) (setf (poly-point-y poly point-index) new-y)) (defmacro POLY-POINT-Z (poly point-index) `(aref (poly-points ,poly) ,point-index 2)) (defun SET-POLY-POINT-Z (poly point-index new-z) (unless (typep new-z 'integer) (setf (poly-integerp poly) nil)) (setf (poly-point-z poly point-index) new-z)) (defun POLY-POINT (poly point-index) (let ((type (poly-type poly)) (points (poly-points poly))) (if (or (eq type :2d) (eq type :2d-relative)) (values (aref points point-index 0) (aref points point-index 1)) (values (aref points point-index 0) (aref points point-index 1) (aref points point-index 2))))) (def-nargs-macro SET-POLY-POINT (poly point-index x y &optional z) "Set the polygon vertex coordinates of the point at point-index in poly to the specified values" (4 'set-poly-point2) (5 'set-poly-point3)) (defun SET-POLY-POINT2 (poly point-index x y) (let ((points (poly-points poly))) (unless (and (typep x 'integer) (typep y 'integer)) (setf (poly-integerp poly) nil)) (setf (aref points point-index 0) x) (setf (aref points point-index 1) y))) (defun SET-POLY-POINT3 (poly point-index x y z) (let ((points (poly-points poly))) (unless (and (typep x 'integer) (typep y 'integer) (typep z 'integer)) (setf (poly-integerp poly) nil)) (setf (aref points point-index 0) x) (setf (aref points point-index 1) y) (setf (aref points point-index 2) z))) ;---------------------------------------------------------------- ;;; Viewports (defstruct (viewport (:print-function print-viewport) (:constructor make-viewport (left right bottom top))) ; these values are fractions. min = 0, max = 1.0 left right bottom top) (defun print-viewport (viewport stream depth) depth (format stream "#" (viewport-left viewport) (viewport-right viewport) (viewport-bottom viewport) (viewport-top viewport) #+lispm (zl:%pointer viewport) #-lispm "")) (defun viewport-aspect-ratio (viewport) "Returns the physical aspect ratio of the viewport on the current display device, i.e. the ratio of its width to its height in units of physical linear measure such as millimeters." (* (/ (- (viewport-right viewport) (viewport-left viewport)) (- (viewport-top viewport) (viewport-bottom viewport))) (screen-aspect-ratio))) ;---------------- Environments ---------------- (defstruct (environment (:include viewport) (:print-function print-environment)) display-device (background-color nil) (border-color nil) (label nil) ; (color 1) ; (graphpos-x 0) ; (graphpos-y 0) ; (graphpos-z 0) ; transform ) (defparameter *full-screen-viewport* (make-viewport 0.0 1.0 0.0 1.0)) (defparameter *default-mouse-viewport-border-color* 1) (defun print-environment (environment stream depth) depth (format stream "#" (environment-left environment) (environment-right environment) (environment-top environment) (environment-bottom environment) (environment-display-device environment) (environment-background-color environment) (environment-border-color environment) #+lispm (zl:%pointer environment) #-lispm "")) ;;; environment with a 2d ortho transformation matrix (defstruct (2d-environment (:include environment)) ortho-left ortho-right ortho-top ortho-bottom ) ;;; environment with a 3d ortho transformation matrix (defstruct (3d-environment (:include environment)) ortho-left ortho-right ortho-top ortho-bottom ortho-near ortho-far ) ;;; environment with a perspective transformation matrix (defstruct (perspective-environment (:include environment)) field-of-view-angle aspect-ratio near-clipping-plane far-clipping-plane ) (defparameter *full-screen-environment* (make-environment :left 0 :right 1 :bottom 0 :top 1)) (defvar *current-environment* *full-screen-environment*) (defun %set-environment (environment) (setq *current-environment* environment) (if (environment-display-device environment) (set-display-device (environment-display-device environment))) (set-viewport environment) (when (environment-background-color environment) (set-color (environment-background-color environment)) (fill-viewport)) (when (environment-border-color environment) (set-viewport *full-screen-viewport*) (ortho 0.0 1.0 0.0 1.0) (set-color (environment-border-color environment)) (rectangle (max 0.0 (- (environment-left environment) .001)) (max 0.0 (- (environment-bottom environment) .001)) (min 1.0 (+ .001 (environment-right environment))) (min 1.0 (+ .001 (environment-top environment)))) (set-viewport environment)) (when (environment-label environment) (ortho 0 1 0 1) (set-color (if (environment-border-color environment) (environment-border-color environment) 7)) (set-text-pos .05 .95) (string-out (environment-label environment))) (case (type-of environment) (perspective-environment (perspective (perspective-environment-field-of-view-angle environment) (perspective-environment-aspect-ratio environment) (perspective-environment-near-clipping-plane environment) (perspective-environment-far-clipping-plane environment))) (3d-environment (ortho (3d-environment-ortho-left environment) (3d-environment-ortho-right environment) (3d-environment-ortho-top environment) (3d-environment-ortho-bottom environment) (3d-environment-ortho-near environment) (3d-environment-ortho-far environment))) (2d-environment (ortho (2d-environment-ortho-left environment) (2d-environment-ortho-right environment) (2d-environment-ortho-top environment) (2d-environment-ortho-bottom environment))) (environment ;; do nothing every thing is cool!!! NIL) ) ) (defun %mouse-environment-shape (environment) (let ((mouse-viewport-border-color (if (environment-border-color environment) (environment-border-color environment) *default-mouse-viewport-border-color*))) (if (environment-display-device environment) (set-display-device (environment-display-device environment))) (set-viewport *full-screen-viewport*) (set-color mouse-viewport-border-color) (ortho 0.0 1.0 0.0 1.0) (with-vista-mouse (multiple-value-bind (b1 first-x first-y) (get-mouse-click t) ; (do ((last-x first-x) (last-y first-y)) ; ((mouse-click-p)) ; (multiple-value-bind (b x y) (get-mouse-state) ; (zl:process-allow-schedule) ;make sure cursor can track while dragging. ; (drawing ; (set-color 0) ; (rectangle first-x first-y last-x last-y) ; (set-color mouse-viewport-border-color) ; (rectangle first-x first-y x y) ; (setq last-x x last-y y)))) (multiple-value-bind (b2 last-x last-y) (get-mouse-click t) (if (< first-x last-x) (setf (environment-left environment) first-x (environment-right environment) last-x) (setf (environment-left environment) last-x (environment-right environment) first-x)) (if (< first-y last-y) (setf (environment-bottom environment) first-y (environment-top environment) last-y) (setf (environment-bottom environment) last-y (environment-top environment) first-y)) ; (print (list first-x last-x first-y last-y)) )) ) (%set-environment environment))) ;---------------------------------------------------------------- ;;; Hacks (defun shade-colors (col1 r1 g1 b1 col2 r2 g2 b2) "Set up a range of colors" (do* ((ncolors (float (- col2 col1))) (dr (/ (- r2 r1) ncolors)) (dg (/ (- g2 g1) ncolors)) (db (/ (- b2 b1) ncolors)) (color col1 (+ color 1)) (r r1 (+ r dr)) (g g1 (+ g dg)) (b b1 (+ b db))) ((> color col2)) (set-map-color color r g b))) (defun frob-colors (&optional (end 100) (start 1)) "Random shades" (format t "~&Type any character to exit.") (do () ((read-char-no-hang)) (shade-colors start (random 1.0s0)(random 1.0s0)(random 1.0s0) end (random 1.0s0)(random 1.0s0)(random 1.0s0))) (format t "~%")) ;---------------------------------------------------------------- ;;; Demos #+lispm (defvar *demo-list* '(("Exit" :funcall exit-demo :documentation "Exit the Demo Menu" :font fonts:tr12bi))) #-lispm (defvar *demo-list* '(("Exit" :funcall exit-demo :documentation "Exit the Demo Menu"))) (defvar *demo-menu* nil) #+lispm (defun defdemo (name fcn-or-form documentation &optional file) "Define a Demonstration NAME is the name of the demo which will appear in menus FCN-OR-FORM is either a list which is evaled or a function to be funcalled DOCUMENTATION is a string describing the demo FILE is the name of the file containing the demo" (setq *demo-list* (cons `(,name ,(if (listp fcn-or-form) :eval :funcall) ,fcn-or-form :documentation ,documentation :font fonts:tr12b ) (delete (assoc name *demo-list* :test #'equal) *demo-list*)))) #-lispm (defun defdemo (name fcn-or-form documentation &optional file) "Define a Demonstration NAME is the name of the demo which will appear in menus FCN-OR-FORM is either a list which is evaled or a function to be funcalled DOCUMENTATION is a string describing the demo FILE is the name of the file containing the demo" (setq *demo-list* (cons `(,name ,(if (listp fcn-or-form) :eval :funcall) ,fcn-or-form :documentation ,documentation ) (delete (assoc name *demo-list* :test #'equal) *demo-list*)))) (defun exit-demo () (throw 'exit-demo nil)) #+lispm (defun demo () (when (null *demo-menu*) (setq *demo-menu* (tv:make-window 'tv:momentary-menu :label '(:string "Choose a Demo" :font fonts:tr12b)))) (zl:send *demo-menu* :set-item-list *demo-list*) (catch 'exit-demo (do () (()) (tv:expose-window-near *demo-menu* '(:mouse)) (zl:send *demo-menu* :choose)))) #-lispm (defun demo () (let ((n 0) item) (dolist (item *demo-list*) (incf n) (format t "~&~d. ~a" n (car item))) (do () ((and (typep (progn (format t "~%~&Choose a Demo: ") (setq n (read))) 'integer) (<= n (length *demo-list*)) (> n 0)))) (setq item (nth (1- n) *demo-list*)) (cond ((get item :funcall) (funcall (get item :funcall))) ((get item :eval) (eval (get item :eval))) (t (error "bad item")))))