More md2 handling
[lodematron.git] / file-md2.lisp
blob0742baece4cdfd473cd05b4bbc37c514ed76fb2e
2 (in-package :lodematron)
4 (defun null-terminate (vector)
5 "Return the given sequence stripped of trailing zeros"
6 (let
7 ((zeroat (position 0 vector)))
8 (if zeroat
9 (subseq vector 0 zeroat)
10 vector)))
12 (defparameter *MD2-ANORMS*
13 '#(
14 '( -0.525731 0.000000 0.850651 )
15 '( -0.442863 0.238856 0.864188 )
16 '( -0.295242 0.000000 0.955423 )
17 '( -0.309017 0.500000 0.809017 )
18 '( -0.162460 0.262866 0.951056 )
19 '( 0.000000 0.000000 1.000000 )
20 '( 0.000000 0.850651 0.525731 )
21 '( -0.147621 0.716567 0.681718 )
22 '( 0.147621 0.716567 0.681718 )
23 '( 0.000000 0.525731 0.850651 )
24 '( 0.309017 0.500000 0.809017 )
25 '( 0.525731 0.000000 0.850651 )
26 '( 0.295242 0.000000 0.955423 )
27 '( 0.442863 0.238856 0.864188 )
28 '( 0.162460 0.262866 0.951056 )
29 '( -0.681718 0.147621 0.716567 )
30 '( -0.809017 0.309017 0.500000 )
31 '( -0.587785 0.425325 0.688191 )
32 '( -0.850651 0.525731 0.000000 )
33 '( -0.864188 0.442863 0.238856 )
34 '( -0.716567 0.681718 0.147621 )
35 '( -0.688191 0.587785 0.425325 )
36 '( -0.500000 0.809017 0.309017 )
37 '( -0.238856 0.864188 0.442863 )
38 '( -0.425325 0.688191 0.587785 )
39 '( -0.716567 0.681718 -0.147621 )
40 '( -0.500000 0.809017 -0.309017 )
41 '( -0.525731 0.850651 0.000000 )
42 '( 0.000000 0.850651 -0.525731 )
43 '( -0.238856 0.864188 -0.442863 )
44 '( 0.000000 0.955423 -0.295242 )
45 '( -0.262866 0.951056 -0.162460 )
46 '( 0.000000 1.000000 0.000000 )
47 '( 0.000000 0.955423 0.295242 )
48 '( -0.262866 0.951056 0.162460 )
49 '( 0.238856 0.864188 0.442863 )
50 '( 0.262866 0.951056 0.162460 )
51 '( 0.500000 0.809017 0.309017 )
52 '( 0.238856 0.864188 -0.442863 )
53 '( 0.262866 0.951056 -0.162460 )
54 '( 0.500000 0.809017 -0.309017 )
55 '( 0.850651 0.525731 0.000000 )
56 '( 0.716567 0.681718 0.147621 )
57 '( 0.716567 0.681718 -0.147621 )
58 '( 0.525731 0.850651 0.000000 )
59 '( 0.425325 0.688191 0.587785 )
60 '( 0.864188 0.442863 0.238856 )
61 '( 0.688191 0.587785 0.425325 )
62 '( 0.809017 0.309017 0.500000 )
63 '( 0.681718 0.147621 0.716567 )
64 '( 0.587785 0.425325 0.688191 )
65 '( 0.955423 0.295242 0.000000 )
66 '( 1.000000 0.000000 0.000000 )
67 '( 0.951056 0.162460 0.262866 )
68 '( 0.850651 -0.525731 0.000000 )
69 '( 0.955423 -0.295242 0.000000 )
70 '( 0.864188 -0.442863 0.238856 )
71 '( 0.951056 -0.162460 0.262866 )
72 '( 0.809017 -0.309017 0.500000 )
73 '( 0.681718 -0.147621 0.716567 )
74 '( 0.850651 0.000000 0.525731 )
75 '( 0.864188 0.442863 -0.238856 )
76 '( 0.809017 0.309017 -0.500000 )
77 '( 0.951056 0.162460 -0.262866 )
78 '( 0.525731 0.000000 -0.850651 )
79 '( 0.681718 0.147621 -0.716567 )
80 '( 0.681718 -0.147621 -0.716567 )
81 '( 0.850651 0.000000 -0.525731 )
82 '( 0.809017 -0.309017 -0.500000 )
83 '( 0.864188 -0.442863 -0.238856 )
84 '( 0.951056 -0.162460 -0.262866 )
85 '( 0.147621 0.716567 -0.681718 )
86 '( 0.309017 0.500000 -0.809017 )
87 '( 0.425325 0.688191 -0.587785 )
88 '( 0.442863 0.238856 -0.864188 )
89 '( 0.587785 0.425325 -0.688191 )
90 '( 0.688191 0.587785 -0.425325 )
91 '( -0.147621 0.716567 -0.681718 )
92 '( -0.309017 0.500000 -0.809017 )
93 '( 0.000000 0.525731 -0.850651 )
94 '( -0.525731 0.000000 -0.850651 )
95 '( -0.442863 0.238856 -0.864188 )
96 '( -0.295242 0.000000 -0.955423 )
97 '( -0.162460 0.262866 -0.951056 )
98 '( 0.000000 0.000000 -1.000000 )
99 '( 0.295242 0.000000 -0.955423 )
100 '( 0.162460 0.262866 -0.951056 )
101 '( -0.442863 -0.238856 -0.864188 )
102 '( -0.309017 -0.500000 -0.809017 )
103 '( -0.162460 -0.262866 -0.951056 )
104 '( 0.000000 -0.850651 -0.525731 )
105 '( -0.147621 -0.716567 -0.681718 )
106 '( 0.147621 -0.716567 -0.681718 )
107 '( 0.000000 -0.525731 -0.850651 )
108 '( 0.309017 -0.500000 -0.809017 )
109 '( 0.442863 -0.238856 -0.864188 )
110 '( 0.162460 -0.262866 -0.951056 )
111 '( 0.238856 -0.864188 -0.442863 )
112 '( 0.500000 -0.809017 -0.309017 )
113 '( 0.425325 -0.688191 -0.587785 )
114 '( 0.716567 -0.681718 -0.147621 )
115 '( 0.688191 -0.587785 -0.425325 )
116 '( 0.587785 -0.425325 -0.688191 )
117 '( 0.000000 -0.955423 -0.295242 )
118 '( 0.000000 -1.000000 0.000000 )
119 '( 0.262866 -0.951056 -0.162460 )
120 '( 0.000000 -0.850651 0.525731 )
121 '( 0.000000 -0.955423 0.295242 )
122 '( 0.238856 -0.864188 0.442863 )
123 '( 0.262866 -0.951056 0.162460 )
124 '( 0.500000 -0.809017 0.309017 )
125 '( 0.716567 -0.681718 0.147621 )
126 '( 0.525731 -0.850651 0.000000 )
127 '( -0.238856 -0.864188 -0.442863 )
128 '( -0.500000 -0.809017 -0.309017 )
129 '( -0.262866 -0.951056 -0.162460 )
130 '( -0.850651 -0.525731 0.000000 )
131 '( -0.716567 -0.681718 -0.147621 )
132 '( -0.716567 -0.681718 0.147621 )
133 '( -0.525731 -0.850651 0.000000 )
134 '( -0.500000 -0.809017 0.309017 )
135 '( -0.238856 -0.864188 0.442863 )
136 '( -0.262866 -0.951056 0.162460 )
137 '( -0.864188 -0.442863 0.238856 )
138 '( -0.809017 -0.309017 0.500000 )
139 '( -0.688191 -0.587785 0.425325 )
140 '( -0.681718 -0.147621 0.716567 )
141 '( -0.442863 -0.238856 0.864188 )
142 '( -0.587785 -0.425325 0.688191 )
143 '( -0.309017 -0.500000 0.809017 )
144 '( -0.147621 -0.716567 0.681718 )
145 '( -0.425325 -0.688191 0.587785 )
146 '( -0.162460 -0.262866 0.951056 )
147 '( 0.442863 -0.238856 0.864188 )
148 '( 0.162460 -0.262866 0.951056 )
149 '( 0.309017 -0.500000 0.809017 )
150 '( 0.147621 -0.716567 0.681718 )
151 '( 0.000000 -0.525731 0.850651 )
152 '( 0.425325 -0.688191 0.587785 )
153 '( 0.587785 -0.425325 0.688191 )
154 '( 0.688191 -0.587785 0.425325 )
155 '( -0.955423 0.295242 0.000000 )
156 '( -0.951056 0.162460 0.262866 )
157 '( -1.000000 0.000000 0.000000 )
158 '( -0.850651 0.000000 0.525731 )
159 '( -0.955423 -0.295242 0.000000 )
160 '( -0.951056 -0.162460 0.262866 )
161 '( -0.864188 0.442863 -0.238856 )
162 '( -0.951056 0.162460 -0.262866 )
163 '( -0.809017 0.309017 -0.500000 )
164 '( -0.864188 -0.442863 -0.238856 )
165 '( -0.951056 -0.162460 -0.262866 )
166 '( -0.809017 -0.309017 -0.500000 )
167 '( -0.681718 0.147621 -0.716567 )
168 '( -0.681718 -0.147621 -0.716567 )
169 '( -0.850651 0.000000 -0.525731 )
170 '( -0.688191 0.587785 -0.425325 )
171 '( -0.587785 0.425325 -0.688191 )
172 '( -0.425325 0.688191 -0.587785 )
173 '( -0.425325 -0.688191 -0.587785 )
174 '( -0.587785 -0.425325 -0.688191 )
175 '( -0.688191 -0.587785 -0.425325 ) )
176 "Normal lookup table used by md2 normal quantizer" )
178 (define-binary-class md2-header
179 ((ident :u32)
180 (version :u32)
181 ;; don't rely on skin info in header - it's most likely balls
182 (skinwidth :u32)
183 (skinheight :u32)
184 (framesize :u32)
185 (nskins :u32)
186 (nvertices :u32)
187 (nuvs :u32)
188 (ntris :u32)
189 (nglcmds :u32)
190 (nframes :u32)
191 (skin-offset :u32)
192 (uv-offset :u32)
193 (tris-offset :u32)
194 (frames-offset :u32)
195 (glcmds-offset :u32)
196 (end-offset :u32)))
199 (define-binary-class md2-skin-name
200 ((name :u8 :array-size 64)))
202 (define-binary-class md2-vector
203 ((x :float32)
204 (y :float32)
205 (z :float32)))
207 (define-binary-class md2-uv
208 ((u :s16)
209 (v :s16)))
211 (define-binary-class md2-triangle
212 ((vertex-indices :u16 :array-size 3)
213 (uv-indices :u16 :array-size 3)))
215 (define-binary-class md2-vertex
216 ((position :u8 :array-size 3)
217 (normal-index :u8)))
219 (define-binary-class md2-frame-header
220 ((scale :md2-vector)
221 (translation :md2-vector)
222 (name :u8 :array-size 16)))
224 (def-mesh-type md2-mesh (simple-mesh) nil
225 :slots
226 ((uvs :accessor uvs-of :initform (make-vector2d-array 0 :adjustable t :fill-pointer 0 ))
227 (uv-index :accessor uvs-tris-of :initform (make-triangle-array 0 :adjustable t :fill-pointer 0))
228 (skin :accessor skin-of)))
230 ;; parsing -- aka file reading
232 (defun parse-md2-skin-names (offset n stream)
233 (file-position stream offset)
234 (let ((result nil))
235 (iterate
236 (for i from 0 below n)
237 (collecting (babel:octets-to-string (read-value :u8 stream :array-size 64))))
238 result))
241 (defun parse-md2-uvs (offset n stream)
242 (file-position stream offset)
243 (let ((result (make-array n)))
244 (iterate
245 (for i from 0 below n)
246 (setf (aref result i) (read-value :md2-uv stream)))
247 result))
249 (defun parse-md2-triangles (offset n stream)
250 (file-position stream offset)
251 (let ((result (make-array n)))
252 (iterate
253 (for i from 0 below n)
254 (setf (aref result i) (read-value :md2-triangle stream)))
255 result))
258 (defun parse-md2-frames (offset n size nverts stream)
259 "Return a hash table that maps a set of frame names to vertices"
260 (file-position stream offset)
261 (let ((frames (make-hash-table :test 'equal :size n)))
262 (iterate
263 (for i from 0 below n)
264 (file-position stream (+ offset (* i size)))
265 (let* ((header (read-value :md2-frame-header stream))
266 (vertices (make-array (list nverts)))
267 (name (babel:octets-to-string (null-terminate (name-of header)))))
268 (format t "Parsing header ~A~%" name)
269 (iterate
270 (for j from 0 below nverts)
271 (setf (aref vertices j) (read-value :md2-vertex stream)))
272 (setf (gethash name frames) (cons header vertices))))
273 frames))
275 ;; posing -- aka animation.
277 (defun pose-vertices (target scale translation vertices)
278 "Return an array of vertices using the given frames scale and translation"
279 (iterate
280 (for index from 0 below (length vertices))
281 (for vertex in-vector vertices)
282 (setf (vertex3d-aref target index)
283 (vertex3d*
284 (+ (* (aref (position-of vertex) 0) (x-of scale)) (x-of translation))
285 (+ (* (aref (position-of vertex) 1) (y-of scale)) (y-of translation))
286 (+ (* (aref (position-of vertex) 2) (z-of scale)) (z-of translation))
287 1.0)))
288 (values))
292 (defun pose-faces (target tris)
293 "Populate na array of faces"
294 (iterate
295 (for tri in-vector tris)
296 (for index from 0 below (length tris))
297 (setf (triangle-aref target index)
298 (triangle*
299 (aref (vertex-indices-of tri) 0)
300 (aref (vertex-indices-of tri) 1)
301 (aref (vertex-indices-of tri) 2))))
302 (values))
304 (defun pose-skin (target uvs skin)
305 "Poopulate an array of vu coordinates"
306 (iterate
307 (for uv in-vector uvs)
308 (vector2d-vector-push-extend
309 (vector2d*
310 (coerce (/ (u-of uv) (width-of skin)) 'single-float)
311 (coerce (/ (v-of uv) (height-of skin)) 'single-float))
312 target))
313 (values))
315 (defun pose-skin-indices (target tris)
316 "Populate an array of face indices to st vectors"
317 (iterate
318 (for st-face in tris)
319 (triangle-vector-push-extend
320 (triangle*
321 (aref (uv-indices-of st-face) 0)
322 (aref (uv-indices-of st-face) 1)
323 (aref (uv-indices-of st-face) 2))
324 target))
325 (values))
328 ;; (collecting (cons
329 ;; (list :vertices
330 ;; (aref (vertex-indices-of tri) 0)
331 ;; (aref (vertex-indices-of tri) 1)
332 ;; (aref (vertex-indices-of tri) 2))
333 ;; (list :uvs
334 ;; (aref (uv-indices-of tri) 0)
335 ;; (aref (uv-indices-of tri) 1)
336 ;; (aref (uv-indices-of tri) 2))))))
338 (defclass md2 ()
339 ((sts :accessor sts-of :initarg :sts)
340 (frames :accessor frames-of :initarg :frames)
341 (tris :accessor tris-of :initarg :tris)
342 (filename :reader filename-of :initarg :fname)
343 (skins :accessor skins-of :initarg :skins)))
346 ;; skins --
347 (defun is-pcx (x)
348 "Test whether file extension is pcx"
349 (let ((name (namestring x))) (string-equal "pcx" (subseq name (- (length name) 3)))))
351 (defun directory-scan (directory-name)
352 "Scan a directory and get a list of skin names"
353 (let ((directory-name-length (length (namestring (merge-pathnames directory-name))))
354 (directory-list (cl-fad:list-directory (merge-pathnames directory-name))))
355 (mapcar #'(lambda (x)
356 (let ((name (namestring x)))
357 (cons
359 (subseq (namestring name) directory-name-length (- (length name) 4)))))
360 (remove-if-not #'is-pcx directory-list))))
362 (defun parse-md2-skins (directory)
363 (let ((result (make-hash-table :test 'equal)))
364 (mapcar #'(lambda (x)
365 (setf (gethash (cdr x) result) (parse-pcx-file (car x))))
366 (directory-scan directory))
367 result))
369 (defun parse-md2-file (filename)
370 "Read in an md2 file from the stream"
371 (with-open-file (stream (merge-pathnames filename) :direction :input :element-type '(unsigned-byte 8))
372 (let*
373 ((header
374 (read-value :md2-header stream)))
375 ;; (format *debug-io* "~D Skins ~D Vertices ~D UVS ~D Tris" (nskins-of header) (nvertices-of header) (nuvs-of header) (ntris-of header))
376 (with-accessors ((frames-offset frames-offset-of) (nframes nframes-of) (framesize framesize-of) (nvertices nvertices-of)) header
377 (let*
378 ((result (make-instance 'md2
379 :fname (merge-pathnames filename)
380 :frames (parse-md2-frames frames-offset nframes framesize nvertices stream)
381 :sts (parse-md2-uvs (uv-offset-of header) (nuvs-of header) stream)
382 :tris (parse-md2-triangles (tris-offset-of header) (ntris-of header) stream)
383 :skins (parse-md2-skins (merge-pathnames (directory-namestring (merge-pathnames filename)))))))
384 result)))))
387 ;; animation --
388 (defmethod pose ((model md2) (mesh md2-mesh) frame-name skin-name)
389 "Set the pose of mesh based on an md2 frame"
390 (let ((frame (gethash frame-name (frames-of model))))
391 (when frame
392 (let ((header (car frame))
393 (vertices (cdr frame))
394 (skin (gethash skin-name (skins-of model))))
395 ;; problem when we texture -- 1:1 mapping betewen index and vertex is lost..
396 ;; maybe md2 mesh with it's own texture - or reallocate and renumber vertices?
397 ;; just a new mesh type with extra attributes
398 (setf (vertices-of mesh) (make-vertex3d-array (length vertices)))
399 (pose-vertices (vertices-of mesh) (scale-of header) (translation-of header) vertices)
400 (setf (faces-of mesh) (make-triangle-array (length (tris-of model))))
401 (pose-faces (faces-of mesh) (tris-of model))
402 (setf (uvs-of mesh) (make-vector2d-array (length (sts-of model)) :fill-pointer 0))
403 (pose-skin (uvs-of mesh) (sts-of model) (gethash skin *textures*))
404 (setf (uvs-tris-of mesh) (make-triangle-array (length (tris-of model)) :fill-pointer 0))
405 (pose-skin-indices (uvs-tris-of mesh) (tris-of model))
406 (setf (skin-of mesh) skin)))
407 mesh))
410 (defmethod repose ((model md2) (mesh md2-mesh) frame-name skin-name)
411 "Change the pose of an exising mesh already initialised with the md2"
412 (let ((frame (gethash frame-name (frames-of model))))
413 (when frame
414 (let ((header (car frame))
415 (vertices (cdr frame))
416 (skin (gethash skin-name (skins-of model))))
417 ;; problem when we texture -- 1:1 mapping betewen index and vertex is lost..
418 ;; maybe md2 mesh with it's own texture - or reallocate and renumber vertices?
419 ;; just a new mesh type with extra attributes
420 (pose-vertices (vertices-of mesh) (scale-of header) (translation-of header) vertices)
421 (pose-faces (faces-of mesh) (tris-of model))
422 (setf (fill-pointer (uvs-of mesh)) 0)
423 (pose-skin (uvs-of mesh) (sts-of model) (gethash skin *textures*))
424 (setf (fill-pointer (uvs-tris-of mesh)) 0)
425 (pose-skin-indices (uvs-tris-of mesh) (tris-of model))
426 (setf (skin-of mesh) skin)))))
430 ;; (let ((
431 ;; (mesh :clear-vertices)
432 ;; (let ((pose-frame (get-frame-of mesh)))
433 ;; (iterate
434 ;; (for vertex in (cdr frame)