Advertisement
Guest User

Wavefront->Lisp->C converter

a guest
Jun 4th, 2012
247
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lisp 9.03 KB | None | 0 0
  1. ;; ====================================================================================================
  2. ;;
  3. ;; file        :wavefront.lisp
  4. ;; date        :2012-06-03
  5. ;; author      :walantis giosis (wg@xraw.de)
  6. ;;
  7. ;; description :Parse a wavefront OBJ file (exported from Blender) into a Lisp object.
  8. ;;
  9. ;; ====================================================================================================
  10.  
  11. (defclass material ()
  12.   ((name               :accessor name-of               :initarg :name               :initform nil)
  13.    (specular-exponent  :accessor specular-exponent-of  :initarg :specular-exponent  :initform 0.0)
  14.    (optical-density    :accessor optical-density-of    :initarg :optical-density    :initform 0.0)
  15.    (dissolve           :accessor dissolve-of           :initarg :dissolve           :initform 0.0)
  16.    (illumination-model :accessor illumination-model-of :initarg :illumination-model :initform 0)
  17.    (ambient-color      :accessor ambient-color-of      :initarg :ambient-color      :initform #(0.0 0.0 0.0))
  18.    (diffuse-color      :accessor diffuse-color-of      :initarg :diffuse-color      :initform #(0.0 0.0 0.0))
  19.    (specular-color     :accessor specular-color-of     :initarg :specular-color     :initform #(0.0 0.0 0.0))
  20.    (diffuse-map        :accessor diffuse-map-of        :initarg :diffuse-map        :initform nil))
  21.   (:documentation ""))
  22.  
  23.  
  24. (defclass face-description ()
  25.   ((vertex-indices  :accessor vertex-indices-of  :initarg :vertex-indices  :initform nil)
  26.    (tvertex-indices :accessor tvertex-indices-of :initarg :tvertex-indices :initform nil)
  27.    (nvertex-indices :accessor nvertex-indices-of :initarg :nvertex-indices :initform nil)
  28.    (smooth-shaded     :accessor is-smooth-shaded     :initarg :smooth-shaded     :initform nil)
  29.    (material-name     :accessor material-name-of     :initarg :material-name     :initform ""))
  30.   (:documentation ""))
  31.  
  32.  
  33. (defclass scene-description ()
  34.   ((vertex-data       :accessor vertex-data-of       :initarg :vertex-data       :initform '())
  35.    (tvertex-data      :accessor tvertex-data-of      :initarg :tvertex-data      :initform '())
  36.    (nvertex-data      :accessor nvertex-data-of      :initarg :nvertex-data      :initform '())
  37.    (face-descriptions :accessor face-descriptions-of :initarg :face-descriptions :initform '())
  38.    (materials         :accessor materials-of         :initarg :materials         :initform '()))
  39.   (:documentation ""))
  40.  
  41. ;; ====================================================================================================
  42.  
  43. (defun parse-string-to-floats (string)
  44.   ;; very helpful for this use case: http://stackoverflow.com/questions/1495475/parsing-numbers-from-strings-in-lisp
  45.   (let ((*read-eval* nil))
  46.     (with-input-from-string (stream string)
  47.       (loop for number = (read stream nil nil)
  48.             while number collect number))))
  49.  
  50.  
  51. (defun replace-all (string part replacement &key (test #'char=))
  52.   ;; got it from: http://cl-cookbook.sourceforge.net/strings.html
  53.   "Returns a new string in which all the occurences of the part
  54. is replaced with replacement."
  55.   (with-output-to-string (out)
  56.     (loop with part-length = (length part)
  57.        for old-pos = 0 then (+ pos part-length)
  58.        for pos = (search part string
  59.                          :start2 old-pos
  60.                          :test test)
  61.        do (write-string string out
  62.                         :start old-pos
  63.                         :end (or pos (length string)))
  64.        when pos do (write-string replacement out)
  65.        while pos)))
  66.  
  67. (defun basepath (path)
  68.   (subseq path 0 (search "/" path :from-end t)))
  69. ;; ====================================================================================================
  70.  
  71. (defun material-newmtl (name)
  72.   (make-instance 'material :name name))
  73.  
  74.  
  75. (defun material-Ns (material value)
  76.   (setf (specular-exponent-of material) (parse-float value)))
  77.  
  78.  
  79. (defun material-Ka (material rgb)
  80.   (setf (ambient-color-of material) (parse-string-to-floats rgb)))
  81.  
  82.  
  83. (defun material-Kd (material rgb)
  84.   (setf (diffuse-color-of material) (parse-string-to-floats rgb)))
  85.  
  86.  
  87. (defun material-Ks (material rgb)
  88.   (setf (specular-color-of material) (parse-string-to-floats rgb)))
  89.  
  90.  
  91. (defun material-Ni (material value)
  92.   (setf (optical-density-of material) (parse-float value)))
  93.  
  94.  
  95. (defun material-d (material value)
  96.   (setf (dissolve-of material) (parse-float value)))
  97.  
  98.  
  99. (defun material-illum (material value)
  100.   (setf (illumination-model-of material) (parse-integer value)))
  101.  
  102.  
  103. (defun material-map_Kd (material path)
  104.   (setf (diffuse-map-of material) path))
  105.  
  106.  
  107. (defun wavefront-consume-v (scene xyz)
  108.   (push (parse-string-to-floats xyz) (vertex-data-of scene)))
  109.  
  110.  
  111. (defun wavefront-consume-vt (scene uv)
  112.   (push (parse-string-to-floats uv) (tvertex-data-of scene)))
  113.  
  114.  
  115. (defun wavefront-consume-vn (scene xyz)
  116.   (push (parse-string-to-floats xyz) (nvertex-data-of scene)))
  117.  
  118.  
  119. (defun wavefront-consume-f (scene face shading material-name)
  120.   (let* ((has-three-components (not (search "//" face)))
  121.          (clean-string         (replace-all face "/" " "))
  122.          (face                 (make-instance 'face-description :smooth-shaded shading :material-name material-name))
  123.          (values               (parse-string-to-floats clean-string)))
  124.     (if has-three-components
  125.         (setf (vertex-indices-of  face) (list (nth 0 values) (nth 3 values) (nth 6 values))
  126.               (tvertex-indices-of face) (list (nth 1 values) (nth 4 values) (nth 7 values))
  127.               (nvertex-indices-of face) (list (nth 2 values) (nth 5 values) (nth 8 values)))
  128.         (setf (tvertex-indices-of face) (list (nth 0 values) (nth 2 values) (nth 4 values))
  129.               (nvertex-indices-of face) (list (nth 1 values) (nth 3 values) (nth 5 values))))
  130.     (push face (face-descriptions-of scene))))
  131.  
  132.  
  133. (defun wavefront-consume-s (scene value)
  134.   (declare (ignore scene))
  135.   (if (string-equal value "off")
  136.       NIL
  137.       T))
  138.  
  139.  
  140. (defun wavefront-consume-usemtl (scene value)
  141.   (declare (ignore scene))
  142.   value)
  143.  
  144.  
  145. (defun wavefront-consume-mtllib (scene value path)
  146.   (with-open-file (in (concatenate 'string path "/" value)
  147.                       :direction :input)
  148.     (let (line
  149.           current-material
  150.           (material-library (make-hash-table))
  151.           (valid-tokens     '("Ns" "Ka" "Kd" "Ks" "Ni" "d" "illum" "map_Kd")))
  152.       (loop
  153.          (setf line (read-line in nil nil nil))
  154.          (when (null line)
  155.            (return))
  156.          (when (> (length line) 0)
  157.            (let* ((pos   (search " " line))
  158.                   (token (subseq line 0 pos)))
  159.              (cond
  160.                ((string-equal token "newmtl")
  161.                 (setf current-material (funcall (read-from-string (concatenate 'string "material-" token)) (subseq line (1+ pos)))
  162.                       (gethash (name-of current-material) material-library) current-material))
  163.                ((member token valid-tokens :test 'string-equal)
  164.                 (funcall (read-from-string (concatenate 'string "material-" token)) current-material (subseq line (1+ pos))))
  165.                ((string-equal token "#") NIL)
  166.                (:otherwise (error "wavefront mtllib converter: unhandled token ~A in path ~A.~%" token path))))))
  167.       (push material-library (materials-of scene)))))
  168.  
  169.  
  170. (defun wavefront (path)
  171.   (with-open-file (in path
  172.                       :direction :input)
  173.     (let (line
  174.           current-shading
  175.           current-material
  176.           (vertex-count  0)
  177.           (face-count    0)
  178.           (nvertex-count 0)
  179.           (tvertex-count 0)
  180.           (scene         (make-instance 'scene-description))
  181.           (valid-tokens  '("v" "vt" "vn")))
  182.       (loop
  183.          (setf line (read-line in nil nil nil))
  184.          (when (null line)
  185.            (return))
  186.          (when (> (length line) 0)
  187.            (let* ((pos   (search " " line))
  188.                   (token (subseq line 0 pos)))
  189.              (cond
  190.                ((string-equal token "#") NIL)
  191.  
  192.                ((string-equal token "s")
  193.                 (setf current-shading (funcall (read-from-string (concatenate 'string "wavefront-consume-" token)) scene (subseq line (1+ pos)))))
  194.                
  195.                ((string-equal token "usemtl")
  196.                 (setf current-material (funcall (read-from-string (concatenate 'string "wavefront-consume-" token)) scene (subseq line (1+ pos)))))
  197.                
  198.                ((string-equal token "f")
  199.                 (funcall (read-from-string (concatenate 'string "wavefront-consume-" token)) scene (subseq line (1+ pos)) current-shading current-material))
  200.  
  201.                ((string-equal token "mtllib")
  202.                 (funcall (read-from-string (concatenate 'string "wavefront-consume-" token)) scene (subseq line (1+ pos)) (basepath path)))
  203.  
  204.                ((member token valid-tokens :test 'string-equal)
  205.                 (funcall (read-from-string (concatenate 'string "wavefront-consume-" token)) scene (subseq line (1+ pos))))
  206.                
  207.                (:otherwise (error "wavefront converter: unhandled token ~A in path ~A.~%" token path))))))
  208.       scene)))
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement