From: Geoff Summerhayes
Subject: CAPI,complex,and Mandelbrot set
Date: 
Message-ID: <ta7rn5s4t8cdad@corp.supernews.com>
Well, this is my first code in Lisp that is larger than a function, but not much
larger. :-) I wrote it last night and have been tweaking it since then to make
it more elegant and then to make it faster. Any comments or suggestions welcome.
I'm using LW personal on a windows box.

But I do have a question, is there a way under CAPI to do the drawing of the set,
such that the window still responds to messages during the drawing?

Geoff

(defpackage "MANTEST" (:use "COMMON-LISP" "CAPI" "GP"))
(in-package "MANTEST")
(export 'mandel-test)

(defconstant iterations 40)
(defconstant colours (vector :red4 :red3 :red2 :red1
                               :orange4 :orange3 :orange1 :orange1
                               :yellow1 :yellow2 :yellow3 :yellow4
                               :green1 :green2 :green3 :green4
                               :blue1 :blue2 :blue3 :blue4
                               :purple4 :purple3 :purple2 :purple1))
(defconstant colours-length (length colours))

;;; The workhorse calculates numer of iterations for a point
;;; I originally wrote this as iterative, then changed it
;;; to tail-recursive

(defun mandel(x)
  (declare (complex x))
  (labels ((man-help(y count)
                    ;; this is to try and speed the < 4.0 test
                    (let ((ry (realpart y))(iy (imagpart y)))
                      (declare (complex y)(fixnum count))
                      (if (or (= count iterations)
                              ;; this test was originally (< 2.0 (abs y))
                              ;; but I assumed this would be faster since
                              ;; it doesn't require a sqrt
                              (< 4.0 (+ (* ry ry)(* iy iy))))
                              count
                              (man-help (+ x (* y y)) (the fixnum(1+ count)))))))
           (man-help x 0)))

;;; the callback function to paint the pane

(defun callback(pane self x y width height)
  (when (oddp height)(decf height));to make sure x-axis is shown
  (dotimes (py height)
    (dotimes (px width)
      (let ((iter (mandel (complex
                           (- (* 3.0 (/ px width)) 2.1)
                           (- (* 2.4 (/ py height)) 1.2)))))
        (when (/= iter iterations)
          (let ((colour (aref colours (mod iter colours-length))))
            (gp:draw-point pane px py :foreground colour)))))))

(defclass man-pane(drawn-pinboard-object)
  ()
  (:default-initargs
   :display-callback 'callback
   :min-width 120
   :min-height 92))

(defun mandel-test()
  (display (make-container (make-instance 'man-pane)
                           :background :black
                           :title "Mandelbrot")))

From: Wade Humeniuk
Subject: Re: CAPI,complex,and Mandelbrot set
Date: 
Message-ID: <98122a$rsi$1@news3.cadvision.com>
"Geoff Summerhayes" <·············@hNoOtSmPaAiMl.com> wrote in message
···················@corp.supernews.com...
> But I do have a question, is there a way under CAPI to do the drawing of
the set,
> such that the window still responds to messages during the drawing?
>

Yes there are ways.

You can create a seperate lisp (mp:create-process or
mp:process-run-function) process that draws in the window while the main
event process handles window events.  Put some pauses in the drawing routine
so that you will not hog the processor.

Also I believe the main event process handles events on a queue.  There is a
routine to queue "events" (I think actually functions) that are interleaved
with window events.  So you would queue a bit of the drawing work, perform
it, requeue the drawing work and so on.  See capi:execute-with-interface.

I would probably create a new process and let it run to completion and kill
it if you have to draw a different view or exit the window.  There will also
be issues with the window being hidden and redisplay events occuring.  I am
not sure you want the set to be redrawn from scratch every time there is a
redisplay.

Wade
From: Geoff Summerhayes
Subject: Re: CAPI,complex,and Mandelbrot set
Date: 
Message-ID: <ta83gkm25nk403@corp.supernews.com>
"Wade Humeniuk" <········@cadvision.com> wrote in message
·················@news3.cadvision.com...
>
> "Geoff Summerhayes" <·············@hNoOtSmPaAiMl.com> wrote in message
> ···················@corp.supernews.com...
> > But I do have a question, is there a way under CAPI to do the drawing of
> the set,
> > such that the window still responds to messages during the drawing?
> >
>
> Yes there are ways.
>
> You can create a seperate lisp (mp:create-process or
> mp:process-run-function) process that draws in the window while the main
> event process handles window events.  Put some pauses in the drawing routine
> so that you will not hog the processor.
>
> Also I believe the main event process handles events on a queue.  There is a
> routine to queue "events" (I think actually functions) that are interleaved
> with window events.  So you would queue a bit of the drawing work, perform
> it, requeue the drawing work and so on.  See capi:execute-with-interface.
>
> I would probably create a new process and let it run to completion and kill
> it if you have to draw a different view or exit the window.  There will also
> be issues with the window being hidden and redisplay events occuring.  I am
> not sure you want the set to be redrawn from scratch every time there is a
> redisplay.
>
> Wade
>

MP package, got it, thanks. I suspected something was driving multiple
processes from the way the listener behaved while the window was being
drawn, just didn't know where to look. More reading.
My theory, the relatively high cost of professional Lisps is due to
the shipping charges for the manuals. (joke)


Geoff
From: Martin Thornquist
Subject: Re: CAPI,complex,and Mandelbrot set
Date: 
Message-ID: <xunvgpld7sy.fsf@grindaflet.ifi.uio.no>
[ Wade Humeniuk ]

> You can create a seperate lisp (mp:create-process or
> mp:process-run-function) process that draws in the window while the
> main event process handles window events. Put some pauses in the
> drawing routine so that you will not hog the processor.

Note that this can lead to problems; redisplaying a window should be
done in the window's own process. You can make some very hard to spot
bugs by e.g. setting layout-description or calling
gp:invalidate-rectangle in another process, as it only make problems
once in a while.

(Yes, I've been bit by this.)


Martin
-- 
"An ideal world is left as an exercise to the reader."
                                                 -Paul Graham, On Lisp
From: Geoffrey Summerhayes
Subject: Re: CAPI,complex,and Mandelbrot set
Date: 
Message-ID: <Cfzp6.354911$f36.12254783@news20.bellglobal.com>
"Martin Thornquist" <············@ifi.uio.no> wrote in message
····················@grindaflet.ifi.uio.no...

> Note that this can lead to problems; redisplaying a window should be
> done in the window's own process. You can make some very hard to spot
> bugs by e.g. setting layout-description or calling
> gp:invalidate-rectangle in another process, as it only make problems
> once in a while.
>
> (Yes, I've been bit by this.)

So I guess my best bet would be to draw to a process-lockable
section and do the transfer to the window in one fell swoop.
I've been thinking about that anyway, I assume gp:draw-point
uses GDI's SetPixel() and it is well-known to be slow.

Geoff
From: Martin Thornquist
Subject: Re: CAPI,complex,and Mandelbrot set
Date: 
Message-ID: <xun1ys8h781.fsf@spjot.ifi.uio.no>
[ Geoffrey Summerhayes ]

> So I guess my best bet would be to draw to a process-lockable
> section and do the transfer to the window in one fell swoop.

Yes, something like that should probably work. I don't think it's that
difficult to do right, as long as you're aware of what could lead to
problems.


Martin
-- 
"An ideal world is left as an exercise to the reader."
                                                 -Paul Graham, On Lisp