;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; simple random range function
(define (randR l h)
  (+ l (* (rand) (- h l))))

; distance from one work's center to another as go down hall
(define *work-separation* 20)

(define *ceiling-height* 25)

; pillar distance from hall center
(define *pillar-dist* 20)

(define *hall-radius* 15)

; viewer's perspective information
(define *height* 5.5)
(define *lookat-height* 5.55)
(define *fov* 57.5)

; set true to generate the "walkthrough"
(define *anim* #f)

; don't generate scenegraph for icam
(set! *rmode* ())

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; generates a flat sqare patch to specs
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define (square x z)
  (separator
    (scale x 1 z)
    (rotate 90 y-axis)
    (patch "bilinear" 
	   'P '((0.5 0 0.5) (0.5 0 -0.5) (-0.5 0 0.5) (-0.5 0 -0.5)))
    ))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define (pillar)
  (separator
    (surface "matte")
    (color '(.19 .18 .2))
    ;    (displacement "cloth" 'depth .5 'freq 2000)
    (scale .5 *ceiling-height* .5)
    (rotate -90 x-axis)
    (cylinder)
    ))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; defines the gallery environment: ceiling, floor, pillars
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define (place)
  (separator
    (define size '(100 1 750))
    
    ; ceiling
    (separator
      (surface "matte")
      (displacement "cloth" 'depth 1)
      (color '(.53 .48 .6))
      (translate 0 *ceiling-height* 0)
      (scale size)
      (square 1 1)
      )
    
    ;floor
    (separator
      (surface "parquet_plank" 'txtscale 16)    ; thanks Larry!
      (color '(.4 .3 .2))
      (scale size)
      (square 1 1)
      )
    
    ; pillars
    (separator
      (translate 0 0 (* *work-separation* 1.5))
      (for i 1 13 1
	   (translate 0 0 *work-separation*)
	   (separator
	     (translate *pillar-dist* 0 0)
	     (pillar))
	   (separator
	     (translate (- *pillar-dist*) 0 0)
	     (pillar))
	   ))
    ))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; generate one side of a picture frame
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define (frame-side x y z)
  (separator
    (scale x y z)
    (uscale .5)
    (box)
    ))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; generate a picture frame
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define (frame x y z thick)
  ; top
  (separator
    (translate 0 (/ (+ y thick) 2.0) 0)
    (frame-side (+ x (* thick 2)) thick z)
    )
  ; bottom
  (separator
    (translate 0 (/ (+ y (* 1.2 thick)) -2.0) 0)
    (frame-side (+ x (* thick 2)) (* 1.2 thick) z)
    )
  ; left
  (separator
    (translate (/ (+ x thick) 2.0) 0 0)
    (frame-side thick (+ y (* thick 2)) z)
    )
  ; right
  (separator
    (translate (/ (+ x thick) -2.0) 0 0)
    (frame-side thick (+ y (* thick 2)) z)
    )
  )

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; create one framed painting
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define (base-work)
  (separator
    (uscale 2)
    (separator
      (color '(.1 .1 .1))
      (frame 6.40 4.84 .5 .75) 
      )
    (separator
      (scale 6.40 4.84 1)
      (rotate 90 x-axis)
      (square 1 1)
      )))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; create all of the framed paintings
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define (works)
  (separator
    (translate 0 0 (* 2 *work-separation*))
    (for i 1 28 1
	 (translate 0 0 (cond ((<= i 14) *work-separation*)
			      ((> i 14) (- *work-separation*))))
	 (separator
	   (translate (cond ((> i 14) (- *hall-radius*))
			    ((= i 14) 0)
			    ((< i 14) *hall-radius*))
		      6.64 0)
	   (cond ((< i 14) (rotate 90 y-axis))
		 ((= i 14) (rotate 0 y-axis))
		 ((> i 14) (rotate -90 y-axis)))
	   (define txname (string-append "Textures/f" 
					 (number->string i) ".tx"))
	   (surface "paintedplastic" 
		    'texturename txname
		    'Ks .1)
	   (base-work))
	 )))    


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; create all lights: each work has a spotlight
; plus there are lights running up the center pointed at the ceiling
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define (lights)
  (xfm-separator
    (for i 1 15 1
	 (translate 0 0 *work-separation*)
	 
	 (light-shadows "on")
	 
	 (spotlight 'intensity 1000 'from '(0 15 0)
		    'to (list (- *hall-radius*) 4.75 0)
		    'coneangle .8 
		    'conedeltaangle .4
		    'shadow-map-res 256)
	 
	 (spotlight 'intensity 1000 'from '(0 15 0)
		    'to (list *hall-radius* 4.75 0)
		    'coneangle .8
		    'conedeltaangle .4
		    'shadow-map-res 256)
	 
	 (light "spotlight" 'intensity 300 'from '(0 10 0)
		'to '(0 100 0)
		'coneangle 1.4
		'conedeltaangle 1)
	 
	 (if (= i 15)
	     (spotlight 'intensity 1000 'from '(0 15 0)
			'to (list 0 4.75 *work-separation*)
			'coneangle .8 
			'conedeltaangle .4
			'shadow-map-res 256)
	     
	     )
	 
	 (if (= i 1)
	     (spotlight 'intensity 1000 'from '(0 15 0)
			'to (list 0 4.75 (- *work-separation*))
			'coneangle .8 
			'conedeltaangle .4
			'shadow-map-res 256)
	     
	     )
	 )))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; create the floating title
; can either use the polygonal object (which I did, for the shadow)
; or use a transparent textured single rectangle (but then shadow is wrong)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define (title obj)
  (separator
    (translate *hall-radius* 6 (* 1.8 *work-separation*))
    (rotate -90 y-axis)
    (uscale 1.45)
    (if obj
	(begin
	  (surface "matte")
	  (uscale (/ 17.54 2.0))
	  (accad-object "title.obj"))
	(begin
	  (surface "tmap" 
		   'texturename "title.tx"
		   'Ks .1)
	  (square 17.54 3.5))
	)
    ))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; create the entrance/exit from a frame
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define (door)
  (separator
    (translate 0 4.75 0)
    (color '(.1 .1 .1))
    (surface "matte")
    (frame 12.80 9.68 10 .75) 
    ))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; camera positions for single frame rendering
; there are 15 positions, and four cardinal directions
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define *cam-from* ())
(define *cam-to* ())

(define (place-cam position-num direction)
  (begin
    (set! *cam-from* (list 0 *height* (* position-num *work-separation*)))
    
    (set! *cam-to* (cond ((eq? direction 'n) 
			  (list (* (- (* (mod position-num 2) 2) 1) .05)
				*lookat-height* 
				(+ 1 (* position-num *work-separation*))))
			 
			 ((eq? direction 's)
			  (list (* (- (* (mod position-num 2) 2) 1) .05)
				*lookat-height* 
				(- (* position-num *work-separation*) 1)))
			 
			 ((eq? direction 'w)
			  (list 1 
				*lookat-height* 
				(+ (* *work-separation* position-num)
				   (* (- (* (mod position-num 2) 2) 1) .05))))
			 
			 ((eq? direction 'e)
			  (list -1 
				*lookat-height* 
				(+ (* *work-separation* position-num)
				   (* (- (* (mod position-num 2) 2) 1) .05))))
			 ))))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; create the entire environment
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define (make-world)
  (world
    (if *anim*
	(model "camera" (cam.tz cam.ry)
	  (translate 0 *height* (cam.tz))
	  (rotate (cam.ry) y-axis)
	  (camera "main" "perspective" 'from '(0 0 0) 'to '(0 0 1) 'fov *fov*)
	  )
	(camera "main" "perspective" 'from *cam-from* 'to *cam-to* 'fov *fov*)
	)
    (atmosphere "fog" 'distance 75 'background '(0 0 0))
    (lights)
    (place)
    (works)
    (title #f)
    (door)
    ))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
((render 'reset))
(set! *rmode* ())

; should shadow maps be regenerated?
((render 'make-shadow-maps) ())

; render wireframe
;((render 'set-renderer!) "render -vector")

; render on other machines
;((render 'set-renderer!) "time netrender -h thinice")


; set rendered frame size
;((render 'set-option!) '(ri-format 160 80 1))
;((render 'set-option!) '(ri-format 320 160 1))
((render 'set-option!) '(ri-format 640 320 1))


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; render the single frames from 15 positions, in all four directions
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;north
(for i 1 15 1
     (begin
       (place-cam i 'n) (make-world)
       ((render 'to-file) (string-append "HomeFrames/north.rle." 
					 (number->string i)))
       (render "main")
      (gc)
       ))
;east
(print 'east)
(for i 1 15 1
     (begin
       (print i)
       (place-cam i 'e) (make-world)
       ((render 'to-file) (string-append "HomeFrames/east.rle." 
					 (number->string i)))
       (render "main")
       (gc)
       ))
;south
(print 'south)
(for i 1 15 1
     (begin
       (print i)
       (place-cam i 's) (make-world)
       ((render 'to-file) (string-append "HomeFrames/south.rle." 
					 (number->string i)))
       (render "main")
       (gc)
       ))
;west
(print 'west)
(for i 1 15 1
     (begin
       (print i)
       (place-cam i 'w) (make-world)
       ((render 'to-file) (string-append "HomeFrames/west.rle." 
					 (number->string i)))
       (render "main")
       (gc)
       ))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; render animation
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(set! *anim* #t)
((render 'set-option!) '(ri-format 320 160 1))

; camera avars
(load-avars "camera.adb")
(if *anim*
    (begin
      (make-world)
      (print 'animation)
      (define *num-frames* 450)
      (for i 99 *num-frames* 1
	   (begin
	     (set-time! i)
	     ((render 'to-file) 
	      (string-append "HomeFrames/Anim/frame." (number->string i)))
	     (render "main")
	     (gc)
	     ))
      ))

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