;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;;

;;  OpenGL Shader Test

;;

;;  This OpenGL shader example uses a shader from the

;;  open GL shading language book: 16.6 Vertex Noise

;;

;;  You will need both: noise.frag and noise.vert

;;  in your /tmp directory

;;  

;;  You can download them from here:

;;  http://developer.3dlabs.com/downloads/glsldemo/glsldemo-src-3.8.zip

;;  Chapter 16 Orange Book Vertex Noise.

;;  

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;


;; define a custom opengl context with the params

;; NSOpenGLPFADoubleBuffer, NSOpenGLPFADepthSize, (NSOpenGLPixelFormatAttribute)24, 0

(define *gl* (gl:make-opengl #(5 12 24 0)))


; uniforms

(define lightposition 0)

(define surfacecolor 0)

(define offset 0)

(define scalein 0)

(define scaleout 0)


; shader + program

(define program -1)

(define verts -1)

(define frags -1)


; init opengl

(define init

   (lambda ()

      (gl:clear-color *gl* 0.0 0.0 0.0 0.0)

      (gl:shade-model *gl* *gl:smooth*)

      (gl:enable *gl* *gl:depth-test*)))


(define init-lights

   (lambda ()      

      (gl:enable *gl* *gl:lighting*)

      (gl:enable *gl* *gl:light0*)))


; init shader

(define init-shader

   (lambda (vert-source frag-source)

      (set! verts (gl:create-shader *gl* *gl:vertex-shader*))

      (set! frags (gl:create-shader *gl* *gl:fragment-shader*))

      (gl:shader-source *gl* verts (objc:call "NSString" "stringWithContentsOfFile:encoding:error:"

                                              vert-source

                                              4

                                              0))

      (gl:shader-source *gl* frags (objc:call "NSString" "stringWithContentsOfFile:encoding:error:"

                                              frag-source

                                              4

                                              0))

      (gl:compile-shader *gl* verts)

      (gl:compile-shader *gl* frags)

      (gl:get-shader-info-log *gl* verts)

      (gl:get-shader-info-log *gl* frags)

      (set! program (gl:create-program *gl*))

      (gl:attach-shader *gl* program verts)

      (gl:attach-shader *gl* program frags)

      (gl:link-program *gl* program)

      (gl:get-program-info-log *gl* program)

      (gl:use-program *gl* program)))


; init uniforms

(define init-uniforms

   (lambda ()

      (set! lightposition (gl:get-uniform-location *gl* program "LightPosition"))

      (set! surfacecolor (gl:get-uniform-location *gl* program "SurfaceColor"))

      (set! offset (gl:get-uniform-location *gl* program "Offset"))

      (set! scalein (gl:get-uniform-location *gl* program "ScaleIn"))

      (set! scaleout (gl:get-uniform-location *gl* program "ScaleOut"))))

      

; init projection view

(define view

   (lambda ()

      (gl:viewport *gl* 0 0 640 480)

      (gl:matrix-mode *gl* *gl:projection*)

      (gl:load-identity *gl*)

      (glu:perspective *gl* 60.0 (/ 640 480) 1.0 50.0)

      (gl:matrix-mode *gl* *gl:modelview*)

      (gl:load-identity *gl*)))


(define colours (vector .5 .20 .7 .8 .29 .25 .9 .3 .1 .6))


; draw one blob

(define draw-blob

   (lambda (i angle)

      (gl:uniform *gl* surfacecolor .8 .7 (vector-ref colours i))

      (gl:uniform *gl* offset 0 0 0)

      (gl:uniform *gl* scalein (* (/ i 2) (cos angle)))

      (gl:uniform *gl* scaleout (* (/ i 2) (cos angle)))

      (gl:translate *gl* (* i 3) 0 0)

      (glut:solid-cube *gl* 3)))


; draw scene

(define draw-scene

   (lambda (angle)

      (gl:clear *gl* (io:binary-or *gl:depth-buffer-bit* *gl:color-buffer-bit*))

      (gl:push-matrix *gl*)

      (glu:look-at *gl* 13.0 0.0 20.0 13.0 0.0 0.0 0.0 1.0 0.0)


      (gl:uniform *gl* lightposition 0.0 0.0 -10.0)            

      

      (dotimes (i 10)

         (gl:push-matrix *gl*)

         (draw-blob i angle)

         (gl:pop-matrix *gl*))

            

      (gl:pop-matrix *gl*)

      (gl:flush *gl*)

      

      (callback (+ (now) 2000) 'draw-scene (fmod (+ angle .005) 360))))


(init)

(init-shader "/tmp/noise.vert" "/tmp/noise.frag")

(init-uniforms)

(init-lights)

(view)

(draw-scene 1.57)

(gl:open-opengl *gl* #t)

(gfx:hide-menu)


(callback (+ (now) (* 10 *second*)) 'gl:close-opengl *gl*) 

(callback (+ (now) (* 10 *second*)) 'gfx:show-menu)

(callback (+ (now) (* 10 *second*)) 'gl:open-opengl *gl* '(200 200 640 480))