saving and loading images with common lisp opengl
Asked Answered
S

1

7

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)?
Scout answered 28/12, 2013 at 22:40 Comment(0)
S
4
  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

Solmization answered 28/12, 2013 at 23:52 Comment(2)
How can we make this fix the rotation/mirror?Scout
@Scout It was a horizontal mirroring, so I fixed it by scanning the source rows in reverse order (the (- 249 h) part)Solmization

© 2022 - 2024 — McMap. All rights reserved.