1 ;;; guile-assimp, foreign interface to libassimp
2 ;;; Copyright (C) 2014 by Javier Sancho Fernandez <jsf at jsancho dot org>
4 ;;; This program is free software: you can redistribute it and/or modify
5 ;;; it under the terms of the GNU General Public License as published by
6 ;;; the Free Software Foundation, either version 3 of the License, or
7 ;;; (at your option) any later version.
9 ;;; This program is distributed in the hope that it will be useful,
10 ;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
11 ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 ;;; GNU General Public License for more details.
14 ;;; You should have received a copy of the GNU General Public License
15 ;;; along with this program. If not, see <http://www.gnu.org/licenses/>.
18 (define-module (assimp assimp)
19 #:use-module (assimp low-level material)
20 #:use-module (assimp low-level mesh)
21 #:use-module (assimp low-level scene)
22 #:use-module (ice-9 iconv)
23 #:use-module (rnrs bytevectors)
24 #:use-module (system foreign))
26 (define libassimp (dynamic-link "libassimp"))
29 (pointer->procedure '*
30 (dynamic-func "aiImportFile" libassimp)
31 (list '* unsigned-int)))
36 (define-syntax define-type
38 (define (mk-string . args)
43 (symbol->string (syntax->datum a))))
45 (define (mk-symbol . args)
48 (apply mk-string args))))
50 ((_ name parser (field field-proc) ...)
51 (with-syntax ((type? (mk-symbol #'name "?"))
52 (wrap-type (mk-symbol "wrap-" #'name))
53 (unwrap-type (mk-symbol "unwrap-" #'name))
54 (output-string (mk-string "#<" #'name " ~x>"))
55 (type-contents (mk-symbol #'name "-contents")))
57 (define-wrapped-pointer-type name
61 (format p output-string
62 (pointer-address (unwrap-type x)))))
63 (define (type-contents wrapped)
64 (let ((unwrapped (unwrap-type wrapped)))
65 (cond ((= (pointer-address unwrapped) 0)
70 (not (null? (cdr f))))
71 (list (cons 'field (field-proc unwrapped))
74 (define (bv-uint-ref pointer index)
76 (pointer->bytevector pointer 4 index)
81 (define (get-aiString index)
83 (let* ((length (bv-uint-ref pointer index))
84 (data (pointer->bytevector pointer length (+ index 4))))
85 (bytevector->string data (fluid-ref %default-port-encoding)))))
87 (define* (get-pointer index #:optional wrap-proc)
89 (let ((p (bv-uint-ref pointer index)))
92 (let ((p2 (make-pointer p)))
94 (cond (wrap-proc (wrap-proc p2))
97 (define (get-array num-index root-index type)
99 (let ((num (bv-uint-ref pointer num-index))
100 (rootp (make-pointer (bv-uint-ref pointer root-index))))
103 (pointer->bytevector rootp num 0 type)))
107 (define* (get-structs-array num-index root-index struct-size #:optional wrap-proc)
109 (let ((num (bv-uint-ref pointer num-index))
110 (rootp (bv-uint-ref pointer root-index)))
111 (let loop ((i (- num 1)))
115 (let* ((p (make-pointer (+ rootp (* i struct-size))))
116 (wp (if wrap-proc (wrap-proc p) p)))
117 (cons wp (loop (- i 1))))))))))
119 (define* (get-pointer-of-pointers num-index root-index #:optional wrap-proc)
121 (let* ((num (bv-uint-ref pointer num-index))
122 (rootp (make-pointer (bv-uint-ref pointer root-index))))
127 (let* ((p (make-pointer (bv-uint-ref rootp (* 4 i))))
128 (wp (if wrap-proc (wrap-proc p) p)))
129 (cons wp (loop (+ i 1))))))))))
131 (define-syntax define-conversion-type
133 (define (mk-string . args)
138 (symbol->string (syntax->datum a))))
140 (define (mk-symbol . args)
143 (apply mk-string args))))
145 ((_ parser -> name (field-name field-proc) ...)
146 (with-syntax ((type? (mk-symbol #'name "?"))
147 (wrap-type (mk-symbol "wrap-" #'name))
148 (unwrap-type (mk-symbol "unwrap-" #'name))
149 (output-string (mk-string "#<" #'name " ~x>"))
150 (type-contents (mk-symbol #'name "-contents"))
151 (type-parse (mk-symbol #'name "-parse"))
152 ((field-reader ...) (map (lambda (f) (mk-symbol #'name "-" (car f))) #'((field-name field-proc) ...))))
154 (define-wrapped-pointer-type name
156 wrap-type unwrap-type
158 (format p output-string
159 (pointer-address (unwrap-type x)))))
160 (define (type-parse wrapped)
161 (let ((unwrapped (unwrap-type wrapped)))
162 (cond ((= (pointer-address unwrapped) 0)
165 (parser unwrapped)))))
166 (define (type-contents wrapped)
167 (let ((alist (type-parse wrapped)))
168 (list (cons 'field-name (field-proc alist))
170 (define (field-reader wrapped)
171 (let ((alist (type-parse wrapped)))
177 (assoc-ref alist name)))
179 (define (get-element-address root-pointer offset)
180 (make-pointer (+ (pointer-address root-pointer) offset)))
182 (define* (array size-tag root-tag #:key (element-size 4) (element-proc bv-uint-ref))
184 (let ((size (assoc-ref alist size-tag))
185 (root (assoc-ref alist root-tag)))
186 (cond ((= (pointer-address root) 0)
193 (cons (element-proc root (* element-size i))
194 (loop (+ i 1)))))))))))
196 (define (wrap proc wrap-proc)
197 (define (make-wrap element)
199 (cond ((pointer? element)
200 (if (= (pointer-address element) 0)
206 (make-pointer element)))))
212 (let ((res (proc alist)))
218 (define (sized-string string-tag)
220 (let ((s (assoc-ref alist string-tag)))
223 (u8-list->bytevector (list-head (cadr s) (car s)))
224 (fluid-ref %default-port-encoding)))
231 (define-conversion-type parse-aiScene -> scene
232 (flags (field 'mFlags))
233 (root-node (wrap (field 'mRootNode) wrap-node))
234 (meshes (wrap (array 'mNumMeshes 'mMeshes) wrap-mesh))
235 (materials (wrap (array 'mNumMaterials 'mMaterials) wrap-material))
236 (animations (array 'mNumAnimations 'mAnimations))
237 (textures (array 'mNumTextures 'mTextures))
238 (lights (array 'mNumLights 'mLights))
239 (cameras (array 'mNumCameras 'mCameras)))
241 (define (load-scene filename flags)
243 (aiImportFile (string->pointer filename)
261 (define-conversion-type parse-aiNode -> node
262 (name (sized-string 'mName))
263 (transformation (field 'mTransformation))
264 (parent (wrap (field 'mParent) wrap-node))
265 (children (wrap (array 'mNumChildren 'mChildren) wrap-node))
266 (meshes (array 'mNumMeshes 'mMeshes)))
279 (define-conversion-type parse-aiMesh -> mesh
280 (name (sized-string 'mName))
281 (primitive-types (field 'mPrimitiveTypes))
282 (vertices (array 'mNumVertices 'mVertices #:element-proc get-element-address))
283 (faces (wrap (array 'mNumFaces 'mFaces #:element-size 8 #:element-proc get-element-address) wrap-face))
284 (normals (array 'mNumVertices 'mNormals #:element-size 12 #:element-proc get-element-address))
285 (tangents (array 'mNumVertices 'mTangents #:element-size 12 #:element-proc get-element-address))
286 (bitangents (array 'mNumVertices 'mBitangents #:element-size 12 #:element-proc get-element-address))
287 (colors (field 'mColors))
288 (texture-coords (field 'mTextureCoords))
289 (num-uv-components (field 'mNumUVComponents))
290 (bones (array 'mNumBones 'mBones))
291 (material-index (field 'mMaterialIndex))
305 mesh-num-uv-components
312 (define-conversion-type parse-aiMaterial -> material
313 (properties (array 'mNumProperties 'mProperties))
314 (num-allocated (field 'mNumAllocated)))
319 material-num-allocated)
324 (define-conversion-type parse-aiFace -> face
325 (indices (array 'mNumIndices 'mIndices)))