(require :asdf)                 ; need ASDF to load other things
(asdf:load-system :cl-opengl)   ; load OpenGL bindings
(asdf:load-system :cl-glu)      ; load GLU bindings
(asdf:load-system :cl-glut)     ; load GLUT bindings
(defclass rotation-state ()
  ((pyramid-angle :initarg :pyramid-angle :reader pyramid-angle)
   (cube-angle :initarg :cube-angle :reader cube-angle))
  (:default-initargs :pyramid-angle 0.0
                     :cube-angle 0.0))
(defclass my-window (glut:window)
  ((fullscreen :initarg :fullscreen :reader fullscreen-p)
   (rotation-state :initarg :rotation-state :accessor rotation-state)
  )
  (:default-initargs :width 400 :height 300
                     :title "tut05: solid shapes"
                     :x 100 :y 100
                     :mode '(:double :rgb :depth)
                     :fullscreen nil
                     :rotation-state (make-instance 'rotation-state)
                     :tick-interval (round 1000 60)  ; milliseconds per tick
  ))
(defmethod glut:display-window :before ((win my-window))
  (gl:shade-model :smooth)        ; enables smooth shading
  (gl:clear-color 0 0 0 0)        ; background will be black
  (gl:clear-depth 1)              ; clear buffer to maximum depth
  (gl:enable :depth-test)         ; enable depth testing
  (gl:depth-func :lequal)         ; okay to write pixel if its depth
                                  ; is less-than-or-equal to the
                                  ; depth currently written
                                  ; really nice perspective correction
  (gl:hint :perspective-correction-hint :nicest)

  (when (fullscreen-p win)        ; check to see if fullscreen needed
    (glut:full-screen))           ; if so, then tell GLUT

  
)
(defmethod glut:display ((win my-window))
                                  ; clear the color buffer and depth buffer
  (gl:clear :color-buffer-bit :depth-buffer-bit)
  (gl:load-identity)              ; reset the modelview matrix
  (let* ((cur (rotation-state win))
         (pyramid-angle (pyramid-angle cur))
         (cube-angle (cube-angle cur)))
    (gl:translate -1.5 0.0 -6.0)    ; translate left and into the screen
    (gl:with-pushed-matrix
                                        ; rotate around the y-axis
        (gl:rotate pyramid-angle 0.0 1.0 0.0)
        (gl:with-primitives :triangles  ; start drawing triangles
          (gl:color 1.0 0.0 0.0)          ; set the color to red
          (gl:vertex 0.0 1.0 0.0)         ; top vertex (front)
          (gl:color 0.0 1.0 0.0)          ; set the color to green
          (gl:vertex -1.0 -1.0 1.0)       ; bottom-left vertex (front)
          (gl:color 0.0 0.0 1.0)          ; set the color to blue
          (gl:vertex 1.0 -1.0 1.0)        ; bottom-right vertex (front)
          (gl:color 1.0 0.0 0.0)          ; set the color to red
          (gl:vertex 0.0 1.0 0.0)         ; top vertex (right)
          (gl:color 0.0 0.0 1.0)          ; set the color to blue
          (gl:vertex 1.0 -1.0 1.0)        ; bottom-left vertex (right)
          (gl:color 0.0 1.0 0.0)          ; set the color to green
          (gl:vertex 1.0 -1.0 -1.0)       ; bottom-left vertex (right)
          (gl:color 1.0 0.0 0.0)          ; set the color to red
          (gl:vertex 0.0 1.0 0.0)         ; top vertex (back)
          (gl:color 0.0 1.0 0.0)          ; set the color to green
          (gl:vertex 1.0 -1.0 -1.0)       ; bottom-left vertex (back)
          (gl:color 0.0 0.0 1.0)          ; set the color to blue
          (gl:vertex -1.0 -1.0 -1.0)      ; bottom-left vertex (back)
          (gl:color 1.0 0.0 0.0)          ; set the color to red
          (gl:vertex 0.0 1.0 0.0)         ; top vertex (left)
          (gl:color 0.0 0.0 1.0)          ; set the color to blue
          (gl:vertex -1.0 -1.0 -1.0)      ; bottom-left vertex (left)
          (gl:color 0.0 1.0 0.0)          ; set the color to green
          (gl:vertex -1.0 -1.0 1.0)       ; bottom-left vertex (left)
          )
        (gl:with-primitives :quads
          (gl:color 0.0 0.0 1.0)        ; set the color to blue
          (gl:vertex 1.0 -1.0 1.0)      ; front-right corner
          (gl:color 0.0 1.0 0.0)        ; set the color to green
          (gl:vertex 1.0 -1.0 -1.0)     ; back-right corner
          (gl:color 0.0 0.0 1.0)        ; set the color to blue
          (gl:vertex -1.0 -1.0 -1.0)    ; back-left corner
          (gl:color 0.0 1.0 0.0)        ; set the color to green
          (gl:vertex -1.0 -1.0 1.0))    ; front-left corner
        )
    (gl:translate  3.0 0.0 0.0)     ; translate right
    (gl:with-pushed-matrix
                                        ; rotate around the x-axis
        (gl:rotate cube-angle 1.0 0.0 0.0)
        (gl:with-primitives :quads      ; start drawing quadrilaterals
          (gl:color 0.0 1.0 0.0)          ; set the color to green
          (gl:vertex  1.0  1.0 -1.0)      ; right top back
          (gl:vertex -1.0  1.0 -1.0)      ; left top back
          (gl:vertex -1.0  1.0  1.0)      ; left top front
          (gl:vertex  1.0  1.0  1.0)      ; right top front
          (gl:color 1.0 0.5 0.0)          ; set the color to orange
          (gl:vertex  1.0 -1.0  1.0)      ; right bottom front
          (gl:vertex -1.0 -1.0  1.0)      ; left bottom front
          (gl:vertex -1.0 -1.0 -1.0)      ; left bottom back
          (gl:vertex  1.0 -1.0 -1.0)      ; right bottom back
          (gl:color 1.0 0.0 0.0)          ; set the color to red
          (gl:vertex  1.0  1.0  1.0)      ; right top front
          (gl:vertex -1.0  1.0  1.0)      ; left top front
          (gl:vertex -1.0 -1.0  1.0)      ; left bottom front
          (gl:vertex  1.0 -1.0  1.0)      ; right bottom front
          (gl:color 1.0 1.0 0.0)          ; set the color to yellow
          (gl:vertex  1.0 -1.0 -1.0)      ; right bottom back
          (gl:vertex -1.0 -1.0 -1.0)      ; left bottom back
          (gl:vertex -1.0  1.0 -1.0)      ; left top back
          (gl:vertex  1.0  1.0 -1.0)      ; right top back
          (gl:color 0.0 0.0 1.0)          ; set the color to blue
          (gl:vertex -1.0  1.0  1.0)      ; left top front
          (gl:vertex -1.0  1.0 -1.0)      ; left top back
          (gl:vertex -1.0 -1.0 -1.0)      ; left bottom back
          (gl:vertex -1.0 -1.0  1.0)      ; left bottom front
          (gl:color 1.0 0.0 1.0)          ; set the color to magenta
          (gl:vertex  1.0  1.0 -1.0)      ; right top back
          (gl:vertex  1.0  1.0  1.0)      ; right top front
          (gl:vertex  1.0 -1.0  1.0)      ; right bottom front
          (gl:vertex  1.0 -1.0 -1.0)      ; right bottom back
          )
        )
    )          ; do anything specific to this tutorial
  (glut:swap-buffers)             ; swap the buffer onto the screen
)
(defmethod glut:reshape ((win my-window) width height)
  (gl:viewport 0 0 width height)  ; reset the current viewport
  (gl:matrix-mode :projection)    ; select the projection matrix
  (gl:load-identity)              ; reset the matrix

  ;; set perspective based on window aspect ratio
  (glu:perspective 45 (/ width (max height 1)) 1/10 100)
  (gl:matrix-mode :modelview)     ; select the modelview matrix
  (gl:load-identity)              ; reset the matrix

   
)
(defmethod glut:keyboard ((win my-window) key xx yy)
  (declare (ignore xx yy))
  (case key
    ((#\q #\Q #\Escape) (glut:close win))
    ((#\f #\F)                  ; when we get an 'f'
                                ; save whether we're in fullscreen
       (let ((full (fullscreen-p win)))
         (glut:close win)       ; close the current window
         (glut:display-window   ; open a new window with fullscreen toggled
             (make-instance 'my-window
                            :fullscreen (not full)))))
    
  ))
(defmethod glut:keyboard-up ((win my-window) key xx yy)
  (declare (ignore xx yy))
  (case key
    ((#\q #\Q #\Escape) t)
    
  ))
(defmethod glut:tick ((win my-window))
                                ; retrieve the current rotation
  (let* ((cur (rotation-state win))
                                ; retrieve the current angles
         (pyramid (pyramid-angle cur))
         (cube (cube-angle cur)))

    (setf (rotation-state win)  ; replace the rotation state
          (make-instance 'rotation-state
                         :pyramid-angle (+ pyramid 0.2)
                         :cube-angle (+ cube 0.15))))

  (glut:post-redisplay))        ; tell GLUT to redraw
(glut:display-window (make-instance 'my-window))

