just another diary

Tuesday, December 29, 2009

OBJ file format.

For this raytracer I chose to import the OBJ file format as the easiest one to parse.
So here is the first draft implementation of the importing of vertex positions.
This simple code is ready to use, the form is: (take-vertexes "test-file.obj")


(defmacro for-each-line (file line body)
  "Takes all liines from the file one by one."
  `(with-open-file (s ,file :direction :input)
                   (let ((r nil) (eof-reached nil))
                     (loop while (not eof-reached) do
                           (multiple-value-setq (,line eof-reached) (read-line s r))
                           (if ,line ,body)))))



(defmacro read-vertex-data (v-line vertexes index &key count-only)
  "Reads three floats from the given line to the vertexes array starting with index.
Index is increased and returned as a result afterwards."
  `(let* ((trimmed-line (string-trim '(#\Space #\Tab #\Newline) ,v-line)))
     (if (and (> (string-size-in-octets trimmed-line) 2)
              (char= #\v (char trimmed-line 0))
              (or (char= #\Space (char trimmed-line 1))
                  (char= #\Tab (char trimmed-line 1))))
         (let* ((trash1 t) (trash2 t)
                (val 0d0)
                (start-from 2)) ; skip "v " in the string

           (progn
             (multiple-value-setq (val start-from) (read-from-string trimmed-line trash1 trash2 :start start-from))
             (if ,vertexes (setf (aref ,vertexes ,index) (coerce val 'double-float)))
             (incf ,index)
             (multiple-value-setq (val start-from) (read-from-string trimmed-line trash1 trash2 :start start-from))
             (if ,vertexes (setf (aref ,vertexes ,index) (coerce val 'double-float)))
             (incf ,index)
             (multiple-value-setq (val start-from) (read-from-string trimmed-line trash1 trash2 :start start-from))
             (if ,vertexes (setf (aref ,vertexes ,index) (coerce val 'double-float)))
             (incf ,index)
             ,index)))))



(defun take-vertexes (file)
  "Takes all found vertexes from the given file to the given array.
Returns the number of the read floats, not vertexes!"
  (let* ((count
          (let ((i 0)) (for-each-line file line (read-vertex-data line nil i)) i)) ; only count, no store

         (temporar-vertexes (make-array count :element-type 'double-float))
         (actually-read-floats 0))
    (for-each-line file line (read-vertex-data line temporar-vertexes actually-read-floats)) ; read+store

    temporar-vertexes))

2 comments:

  1. http://github.com/death/towers/blob/master/towers.lisp has a different implementation, see LOAD-WF-OBJECT.

    ReplyDelete
  2. Thank you, Xash! This info is really helpful. I tried to find it myself, but didn't succeed.

    ReplyDelete

My Blog List

Powered by Blogger.