[ab] Fast pixel access
Justin Heyes-Jones
justinhj at gmail.com
Mon Nov 27 08:24:23 CST 2006
On 11/27/06, Luke J Crook <luke at balooga.com> wrote:
> Anthony,
>
> I'll add a faster WITH-PIXEL macro which will hopefully provide some
> speedup. CL-GD has something similar and I have been meaning to add this
> to lispbuilder-sdl for a while.
>
> DRAW-PIXEL is faster than DRAW-POINT. DRAW-POINT will lock the surface
> prior to calling DRAW-PIXEL on each pixel write. You can speed things up
> yourself by placing all DRAW-PIXEL calls within a
> WITH-POSSIBLE-LOCK-AND-UPDATE. You really need to make sure that the SDL
> surface is locked prior to hitting the surface directly with a pixel
> read or write, and then unlocked following the write. This is what
> WITH-POSSIBLE-LOCK-AND-UPDATE does.
>
> I think that I have used the rotozoom function in sdl_gfx before and it
> worked for me. I'll try find the example code I used and post it to the
> group.
>
> With regards to accessing a foreign byte array directly from CFFI (as
> opposed to a single element of the array at a time), I believe that this
> is actively being worked on by the CFFI developers. Once we have this
> then most of the functionality provided by sdl_gfx can be replaced by
> Lisp code. Right now the functions performed by sdl_gfx are WAY faster
> than anything that can be done in Lisp.
>
> And thanks for the rotation function below.
>
> - Luke
>
> Anthony Fairchild wrote:
> > Hello again,
> >
> > I've been playing around with lispbuilder-SDL a bit over the holiday
> > weekend and started writing a simple jigsaw puzzle-like game. I'm
> > very happy with what I have so far but I'm running into a bit of
> > slowness when doing direct pixel manipulation, specifically, rotating
> > images.
> >
> > I've looked at rotozoom in the gfx package and I could not get it to
> > work (that's another issue altogether). Rotating an image seemed like
> > such a simple thing anyway, so I wrote my own
> > likely-over-complicated-and-bug-ridden function to do it:
> >
> > (defun rotate-surface(surf degrees)
> > "rotates a surface 0, 90, 180, or 270 degrees"
> > (let ((degrees (normalize-degrees degrees)))
> > (if (= 0 degrees)
> > ;; in the case of 0 degrees, just copy surface
> > (copy-and-blit-surface surf)
> > ;; else do rotation
> > (let* ((w (surf-w surf))
> > (h (surf-h surf))
> > (new-w (if (or (= 90 degrees)
> > (= 270 degrees)) h w))
> > (new-h (if (or (= 90 degrees)
> > (= 270 degrees)) w h))
> > (new-surf (create-surface new-w new-h :surface surf))
> > (new-x (case degrees
> > (90 #'(lambda (x y)(declare (ignore x))(+ (1-
> > new-w) (- 0 y))))
> > (180 #'(lambda (x y)(declare (ignore y))(+ (1-
> > new-w) (- 0 x))))
> > (270 #'(lambda (x y)(declare (ignore x))y))))
> > (new-y (case degrees
> > (90 #'(lambda (x y)(declare (ignore y))x))
> > (180 #'(lambda (x y)(declare (ignore x))(+ (1-
> > new-h) (- 0 y))))
> > (270 #'(lambda (x y)(declare (ignore y))(+ (1-
> > new-h) (- 0 x)))))))
> > (loop :for x :from 0 :to (1- w)
> > :do (loop :for y :from 0 :to (1- h)
> > :do (let ((pixel (get-pixel :position (point x y)
> > :surface surf)))
> > (draw-pixel (funcall new-x x y)
> > (funcall new-y x y) :surface new-surf
> > :color (sdl:sdl_maprgb
> > (sdl:pixelformat sdl:*default-surface*)
> > (color-r pixel)
> > (color-g pixel)
> > (color-b pixel)))
> > #+nil(draw-point :position (point (funcall new-x x y)
> > (funcall new-y x y))
> > :surface new-surf
> > :color pixel))))
> > new-surf))))
> >
> > The function works but the pixel access is very slow. It seems like I
> > need some way to directly access the surface memory, perhaps with a 2d
> > byte array? Maybe this is not possible with CFFI, or maybe the
> > solution is right under my nose and I'm not seeing it.
> >
> > Any suggestions?
Hey guys
I think if you follow Lukes advice and use draw-pixel and avoid
locking and unlocking the surface every draw, it will be a lot faster.
If you want to do a lot of pixel read and writes to a particular
surface format perhaps you could write a custom function using some of
the code from draw-pixel in sdl/drawing-primitives.lisp
The basic code to access an 8 bit pixel, for example, is just ...
(mem-aref pixel-address :unsigned-char offset)
Justin
More information about the application-builder
mailing list