lispgames / cl-sdl2

Common Lisp bindings for SDL2 using C2FFI.
MIT License
304 stars 82 forks source link

I can't figure out how to use RENDER-DRAW-LINES and POINTS*. #121

Closed cestrand closed 5 years ago

cestrand commented 5 years ago

I am new to FFI. I don't know how to draw triangle with render-draw-lines. I've tried using points* as I thought it could convert (list (make-point ...) (make-point ...)) into suitable object but unsuccessful.

(defun equilateral-triangle-points (x y r)
  (list
   (sdl2:make-point x (+ y r))
   (sdl2:make-point (round (+ x
                  (* r (cos (* 7 (/ pi 6))))))
            (round (+ y (* r (sin (* 7 (/ pi 6)))))))
   (sdl2:make-point (round (+ x
                  (* r (cos (* 11 (/ pi 6))))))
            (round (+ y (* r (sin (* 11 (/ pi 6)))))))))

(defun draw-equilateral-triangle (ren x y r)
  (sdl2:render-draw-lines ren
              (points* (equilateral-triangle-points x y r))
              3))
nsrahmad commented 5 years ago

Hello @cestrand,

If you look at the parameter list of points*, it looks like points* &rest points . Which means points* takes any number of points and puts them in a list called points (see Rest parameters section on http://www.gigamonkeys.com/book/functions.html ). What you do above is equivalent of calling (points* (list p1 p2 p3)) i.e calling points* with a single argument which is list of three points.

You need to call it as (points* p1 p2 p3). You can do that by destructuring the list with destructuring-bind:

(defun draw-equilateral-triangle (ren x y r)
  (sdl2:render-draw-lines ren
              (destructuring-bind (p1 p2 p3) (equilateral-triangle-points x y r)
                (sdl2:points* p1 p2 p3))
              3))

Now it should work, however if you run the above code you would see something like:

wrong

where does one side go? To figure that out, You need to look at documentation for SDL_RenderDrawLines. If you see the example there it becomes clear that it draws connected lines, which mean if you call it with three points like p1, p2 and p3 -- it will draw line p1-p2 and p2-p3, i.e you supply three points you get two line. That is exactly what you see above.

To get three lines, you need to provide four points to render-draw-lines. The fourth point is obviously the first point, so final version of draw-equilateral-triangle will be:

(defun draw-equilateral-triangle (ren x y r)
  (sdl2:render-draw-lines ren
              (destructuring-bind (p1 p2 p3) (equilateral-triangle-points x y r)
                (sdl2:points* p1 p2 p3 p1))
              4))

You pass (points* p1 p2 p3 p1) and you get lines p1-p2 , p2-p3 and p3-p1 as seen below:

right

I hope it is helpful and good luck for whatever you will build.

cestrand commented 5 years ago

Thank you @nsrahmad. I really appreciate your comprehensive response.

Best wishes!