use struct for canvas

 - add test for trailing newline in PPM output
 - add function to write PPM to file
1 files changed, 29 insertions(+), 17 deletions(-)

M tracer.lisp
M tracer.lisp +29 -17
@@ 63,17 63,18 @@ 
 (defun blend (c1 c2)
   (vec3* c1 c2))
 
-(defun create-canvas (width height)
-  (make-array (list width height) :initial-element (vector 0 0 0)))
+(defstruct (canvas
+            (:constructor
+             make-canvas (&key width height)))
+  width
+  height
+  (body (make-array (list width height) :initial-element (vector 0 0 0))))
 
-(defun canvas-height (c)
-  (nth 1 (array-dimensions c)))
-
-(defun canvas-width (c)
-  (nth 0 (array-dimensions c)))
+;; (defun create-canvas (width height)
+;;   (make-array (list width height) :initial-element (vector 0 0 0)))
 
 (defun write-pixel (canvas x y color)
-  (setf (aref canvas x y) color))
+  (setf (aref (canvas-body canvas) x y) color))
 
 (defun wrap (text width)
   (setq text (concatenate 'string text " "))

          
@@ 92,7 93,9 @@ 
 
 (defun canvas-pixel-strings (c)
   (labels ((pixel->string (v) (format nil "~s ~s ~s" (Red v) (Green v) (Blue v))))
-    (loop for pixel across (make-array (apply #'* (array-dimensions c)) :displaced-to c)
+    (loop for pixel across
+         (make-array (apply #'* (array-dimensions (canvas-body c)))
+                     :displaced-to (canvas-body c))
        collect (pixel->string pixel))))
 
 (defun canvas->string (c)

          
@@ 216,30 219,30 @@ 
            (float= (BLUE blended-color) 0.04))))
 
 (deftest canvas-properties
-  (let* ((c (create-canvas 10 20))
+  (let* ((c (make-canvas :width 10 :height 20))
          (w (canvas-width c))
          (h (canvas-height c)))
     (check (equalp w 10)
            (equalp h 20)
-           (loop for i across (make-array (* w h) :displaced-to c)
+           (loop for i across (make-array (* w h) :displaced-to (canvas-body c))
               always (equalp i (vector 0 0 0))))))
 
 (deftest canvas-write-pixel
-  (let ((canvas (create-canvas 10 20))
+  (let ((canvas (make-canvas :width 10 :height 20))
         (color (vector 1 0 0)))
     (write-pixel canvas 2 3 color)
-    (check (equalp (aref canvas 2 3) (vector 1 0 0)))))
+    (check (equalp (aref (canvas-body canvas) 2 3) (vector 1 0 0)))))
 
 (deftest check-canvas-pixel-string
-  (let ((c (create-canvas 1 2)))
+  (let ((c (make-canvas :width 1 :height 2)))
     (check (equalp (canvas-pixel-strings c) (list "0 0 0" "0 0 0")))))
 
 (deftest check-canvas-to-string
-  (let ((c (create-canvas 1 2)))
+  (let ((c (make-canvas :width 1 :height 2)))
     (check (equalp (canvas->string c) "0 0 0 0 0 0"))))
 
 (deftest output-canvas-to-ppm
-  (check (equalp (canvas->ppm (create-canvas 3 5))
+  (check (equalp (canvas->ppm (make-canvas :width 3 :height 5))
 "P3
 3 5
 255

          
@@ 247,6 250,9 @@ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
 0 0 0 0 0 0 0 0 0 0
 ")))
 
+(deftest ppm-includes-trailing-newline
+  (let ((c (canvas->ppm (make-canvas :width 3 :height 5))))
+    (check (equalp 0 (position #\Newline (reverse c) :test #'char=)))))
 
 (deftest chapter-2
   (color-vector-getters)

          
@@ 255,8 261,14 @@ 0 0 0 0 0 0 0 0 0 0
   (canvas-write-pixel)
   (check-canvas-pixel-string)
   (check-canvas-to-string)
-  (output-canvas-to-ppm))
+  (output-canvas-to-ppm)
+  (ppm-includes-trailing-newline))
+
+(defun ppm->file (ppm-string path)
+  (with-open-file (stream path :direction :output :if-exists :supersede)
+    (format stream ppm-string)))
 
 (deftest suite
   (chapter-1)
   (chapter-2))
+