[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

drawing to offscreen bitmaps

I've had a few requests for a sample of how to do drawing on an
off-screen bitmap in lisp, so here it is. It works well, and, infact,
the timing isn't that bad either for the fractal it draws (compared
to the equivalent C program):

;; file offscreen.lisp
;; Copyright (C) 1993 John Montbriand.  All Rights Reserved.
;; an example of how to do drawing offscreen on
;; a bitmap and then displaying the results in a window.
;; successive generations of a dragon fractal are displayed
;; on the screen only after each is completed drawing.
(require 'quickdraw)
;; dragonr adapted to lisp from the pascal
;; found in Matthew Zeidenberg's article
;; "Snowflakes and Dragons" appearing
;; in the August 1985 issue of MacWorld (p. 127).
(defun dragonr (x1 y1 x2 y2 x3 y3 n)
  "recursive dragon drawing routine"
  (if (<= n 1)
      (#_MoveTo x1 y1)
      (#_LineTo x2 y2)
      (#_LineTo x3 y3))
    (let* ((x4 (truncate (/ (+ x1 x3) 2)))
           (y4 (truncate (/ (+ y1 y3) 2)))
           (x5 (+ x3 (- x2 x4)))
           (y5 (+ y3 (- y2 y4))))
      (dragonr x2 y2 x4 y4 x1 y1 (1- n))
      (dragonr x2 y2 x5 y5 x3 y3 (1- n)))))
(defun dragon-fractal (h v size n)
  (dragonr (+ h size) v h (- v size) (- h size) v n))
(defun do-dragons (generations)
  (prog* ((extent 250)                  ; size of the window
          (half (truncate (/ extent 2)))        ; the middle
          (mybits (make-bitmap 0 0 extent extent))      ; <- OFFSCREEN bitmap
          (myport (make-record grafport))       ; <- OFFSCREEN grafport
          (wind (make-instance 'window          ; window for showing stuff
                  :view-position #@(10 50)
                  :view-size (make-point extent extent)
                  :window-title "off-screen"
                  :window-type :single-edge-box
                  :erase-anonymous-invalidations nil)))
    (#_OpenPort myport)                 ; open a new grafport
    (with-port myport                   ; and make it the current one
      (#_TextFont #$geneva)
      (#_TextSize 24)
      (#_SetPortBits mybits)            ; set the port's bitmap
      (#_PortSize extent extent)        ; and set the new size
      (dotimes (i generations)
        ;; clear the offscreen bitmap
        (#_EraseRect (pref myport grafport.portrect))
        ;; draw indicator
        (dotimes (j generations)
          (#_MoveTo (+ (* j 8) 16) 1)
          (#_Line 0 (if (= i j) 10 5)))
        ;; draw our picture
        (dragon-fractal half half (truncate (/ half 2)) i)
        (with-pstrs ((s "MCL2 Dragon"))
          (#_MoveTo (+ 7 i) (- extent 7 i))
          (#_DrawString s))
        ;; copy the offscreen drawing to the screen
        (copy-bits mybits
                   (pref (wptr wind) windowrecord.portbits)
                   (pref myport grafport.portrect)
                   (pref (wptr wind) windowrecord.portrect)
    (#_ClosePort myport)                ; close the port + cleanup
    (dispose-record myport)
    (dispose-record mybits)
    (sleep 2)
    (window-close wind)))
;; here's a test run (may take up to 20 seconds on older macs):
(do-dragons 14)
;; end of file offscreen.lisp