Skip to content
Brad Beer edited this page May 10, 2013 · 7 revisions

Drawing on a Texture

For 2D graphics, CLinch uses cl-Cairo2 which is a nice lispy interface to the cario "C" library. Usually to write to a texture we would need to do the following:

  1. Bind the texture.
  2. Map the buffer into memory.
  3. Create a cairo surface for the data.
  4. Create a cairo context for drawing on the surface.
  5. Draw with the context.
  6. Release the context.
  7. Release the surface.
  8. Unmap the buffer.
  9. Unbind the texture. (optional)

Each of these operations are available to the programmer in CLinch, but it's not necessary to use them directly. CLinch uses with-* macros such as with-mapped-buffer, with-surface-for-texture and with-context-for-texture. These macros also allow you to specify internal variables such as the bits variable, width, height, etc. This allows us to easily modify our textures. As usual, we will modify the previous tutorial. This time there are very few changes. Let's start with (init) and modify our texture constructor:

      (setf texture01
        (make-instance 'clinch:texture
                       :width 800
                       :height 800
                       :stride 4
                       :count (* 800 800)
                       :qtype :unsigned-char
                       :target :pixel-unpack-buffer))

Since we are not loading a texture from a file, we just create the texture. Notice we don't need to give it any data, just specify what it should be. Next we need to call the drawing function(s). But before we do that, I thought it would be nice to add a little texture animation to this tutorial. For that we will call our drawing function repeatedly and tell it to draw a different part of the texture each time. At the beginning of the main loop we will add the following:

    (multiple-value-bind (top bottom) (floor frame-count 100)
       (when (zerop bottom)
         (draw-on-texture top)))

So every 100 frames we call (draw-on-texture) with an ever increasing integer. Try it out if you don't know what this does. Finally, we need to add our drawing code:

    (defun draw-on-texture (count)
      (clinch:with-context-for-texture (texture01)
        (case (mod count 7)

          (0 (clinch:clear-cairo-context))
      
          (1 (cairo:set-line-width (* 800 .2))
             (cairo:set-source-rgb 0 0 0)
             (cairo:move-to 0 0)
             (cairo:line-to 800 800)
             (cairo:stroke))

         (2 (cairo:set-line-width (* 800 .2))
            (cairo:set-source-rgb 0 0 0)
            (cairo:move-to 800 0)
            (cairo:line-to 0 800)
            (cairo:stroke))

         (3 (cairo:set-source-rgba 1 0 0 .8)
            (cairo:rectangle 0 0 400 400)
            (cairo:fill-path))
      
         (4 (cairo:set-source-rgba 0 1 0 .6)
            (cairo:rectangle 0 400 400 400)
            (cairo:fill-path))
      
         (5 (cairo:set-source-rgba 0 0 1 .4)
            (cairo:rectangle 400 0 400 400)
            (cairo:fill-path))

         (6 nil))))

There, we cycle through each case and do a different piece of the drawing. If you don't understand cairo, don't worry, you can get a good idea just from reading it out loud. There is one little gotcha, which is the clinch:clear-cairo-contex which is in CLinch, not cairo. They don't have one and I don't know why. It's necessary due to how they treat alpha values and it's non-trivial as well.

And that's it. Compile and run (start) and you should see our fabulous spinning cube again, only now it will start as solid white and end up with a pleasant pattern. Next time we will use the Pango Library to write formatted text onto our cube.

Clone this wiki locally