Question

I have created a graphic using Common Lisp, OpenGL, and glut. Specifically, I am using the library cl-opengl. I wish to save this graphic (which is made with connecting gl:vertex points) to an external file so that I can load it and manipulate it in future programs.

  1. How can I save the graphic drawn to the glut-window?
  2. How can I load a graphic from an image file?
  3. How do I manipulate a loaded image (such as copying, translating and rotating)?
Was it helpful?

Solution

  1. You can use glReadPixels function in your OpenGL frame rendering routine to get the RGB data, and then save it in a picture format with a fitting library. For example, there is the ZPNG in the quicklisp repository to write PNGs: http://www.xach.com/lisp/zpng/#sect-examples

  2. Use an image library to read image data from the file. To follow my earlier example with the PNG format, you can quickload png-read and use it to extract the RGB data.

    (png-read:read-png-file #p"/tmp/1.png")
    (png-read:physical-dimensions p) ;returns width and height in meters
    (png-read:image-data p) ;returns a three-dimensional array of bytes
    
  3. If you are using OpenGL already, just enable orthogonal perspective mode, make a quad face with your image as texture and manipulate the mesh. If you want to paint on a 2D image buffer canvas, pick a library like cairo.

in my SBCL following works:

    (ql:quickload '(:cl-opengl :cl-glu :cl-glut :zpng))

    (defclass hello-window (glut:window) ()
      (:default-initargs :pos-x 100 :pos-y 100 :width 250 :height 250
                 :mode '(:single :rgba) :title "hello"))

    (defmethod glut:display-window :before ((w hello-window))
      ;; Select clearing color.
      (gl:clear-color 0 0 0 0)
      ;; Initialize viewing values.
      (gl:matrix-mode :projection)
      (gl:load-identity)
      (gl:ortho 0 1 0 1 -1 1))

    (defmethod glut:display ((w hello-window))
      (gl:clear :color-buffer)
      (gl:color 0.4 1 0.6)
      (gl:with-primitive :polygon
        (gl:vertex 0.25 0.25 0)
        (gl:vertex 0.75 0.25 0)
        (gl:vertex 0.25 0.55 0))
      (gl:flush))

    (defmethod glut:keyboard ((w hello-window) key x y)
      (declare (ignore x y))
      (when (eql key #\Esc)
        (glut:destroy-current-window))
      (when (eql key #\r)
        (let* ((mypng (make-instance 'zpng:png :width 250 :height 250))
           (imagedata (zpng:data-array mypng))
           (sample1 (gl:read-pixels 0 0 250 250 :bgra :unsigned-byte)))
          (format t "read~%")
          (dotimes (i (expt 250 2))
            (multiple-value-bind (h w) (floor i 250)
              (setf (aref imagedata (- 249 h) w 0) (aref sample1 (+ 2 (* i 4))))
              (setf (aref imagedata (- 249 h) w 1) (aref sample1 (+ 1 (* i 4))))
              (setf (aref imagedata (- 249 h) w 2) (aref sample1 (+ 0 (* i 4))))))
          (zpng:write-png mypng #p"/tmp/readpixels.png"))
        (format t "written~%")))

    (defun rb-hello ()
      (glut:display-window (make-instance 'hello-window)))

Pressing "r" saves the file in /tmp/readpixels.png

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top