Hardware skinning
[dormin.git] / nmo.ml
blobf4c4c233a0f2e7e05f5df430f6c0e6813ef30814
1 open Format;;
3 type subhdr =
4 { off : int
5 ; count : int
8 type surf =
9 { tricount : int
10 ; strcount : int
11 ; name : string
12 ; hdr1 : (int array * float * int32 * int32) array
13 ; hdr2 : (int32 * float * float * int32 array)
14 ; hdr3 : int32 array
17 type surf1 =
18 { size : int
19 ; surf : int
20 ; offs : int
21 ; tri_count : int
22 ; strip_count : int
25 type tex =
26 { texname : string
27 ; nto : (int * int * string) array
28 ; int5 : int32 array
29 ; half1 : int array
30 ; w : int
31 ; h : int
34 type geom =
35 { vertexa : float array
36 ; skin : Skin.skin
37 ; normala : float array
38 ; uva : float array
39 ; colora : string
40 ; surfaces : (int list * surf * GlTex.texture_id lazy_t) list
43 let rsurf1 sbuf =
44 { size = Xff.rint sbuf 0
45 ; surf = Xff.rint sbuf 8
46 ; offs = Xff.rint sbuf 16
47 ; tri_count = Xff.rint sbuf 20
48 ; strip_count = Xff.rint sbuf 24
52 let mag i j k s = sqrt (i*.i +. j*.j +. k*.k +. s*.s);;
54 let verts_in_surf1 surf1 sbuf =
55 let sbuf = Xff.sbufplus sbuf surf1.offs in
56 let r8 = Xff.r8 sbuf in
57 let rec r1 verts pos =
58 let a, b, c, d = r8 pos, r8 (pos+1), r8 (pos+2), r8 (pos+3) in
59 let pos = pos + 4 in
60 let skip pos = r verts pos in
61 match d with
62 | 0x05 when c = 0 -> skip pos
63 | 0x17 when c = 0 -> skip pos
64 | 0x65 -> r verts (pos + 4*c)
65 | 0x68 when a = 1 -> r (verts + c) (pos + 12*c)
66 | 0x68 -> skip (pos + 12*c)
67 | 0x6c -> skip (pos + 16*c)
68 | 0x6d -> skip (pos + 8*c)
69 | 0x6e -> skip (pos + 4*c)
70 | 0x00 when a = 0 && b = 0 && c = 0 -> verts
71 | _ ->
72 let msg = sprintf "geom (a=%x b=%x c=%x d=%x)" a b c d in
73 Xff.sbuferr sbuf pos msg
74 and r verts pos =
75 if pos = surf1.size then verts
76 else r1 verts pos
78 r 0 12
81 let app count pos index pos_incr index_incr f =
82 let rec g p i count = if count = 0 then () else (
83 f p i;
84 g (p + pos_incr) (i + index_incr) (count -1)
86 in g pos (index*index_incr) count
89 let rgeom1 start_index surf1 geom sbuf =
90 let sbuf = Xff.sbufplus sbuf surf1.offs in
91 let r8, r16s, r16, rfloat =
92 Xff.r8 sbuf, Xff.r16s sbuf, Xff.r16 sbuf, Xff.rfloat sbuf
94 let rec r1 counts index prev_count pos =
95 let a, b, c, d = r8 pos, r8 (pos+1), r8 (pos+2), r8 (pos+3) in
96 let pos = pos + 4 in
97 let skip pos = r counts index prev_count pos in
98 let skip2 n = skip (pos+c*n) in
99 match d with
100 | 0x05 when c = 0 -> skip pos
101 | 0x17 when c = 0 -> skip pos
103 | 0x65 ->
104 app c pos index 4 2 (fun pos index ->
105 let u = r16s (pos + 0)
106 and v = r16s (pos + 2) in
107 let u = float u /. 4096.0
108 and v = float v /. 4096.0 in
109 geom.uva.(index + 0) <- u;
110 geom.uva.(index + 1) <- v;
112 skip2 4
114 | 0x68 when a = 1 ->
115 let index = index + prev_count in
116 app c pos index 12 3 (fun pi vi ->
117 geom.vertexa.(vi + 0) <- rfloat (pi + 0);
118 geom.vertexa.(vi + 1) <- rfloat (pi + 4);
119 geom.vertexa.(vi + 2) <- rfloat (pi + 8);
121 r (c :: counts) index c (pos + c*12)
123 | 0x68 when a = 2 ->
124 app c pos index 12 3 (fun pi vi ->
125 let x = rfloat (pi + 0) in
126 let y = rfloat (pi + 4) in
127 let z = rfloat (pi + 8) in
128 geom.normala.(vi + 0) <- x;
129 geom.normala.(vi + 1) <- y;
130 geom.normala.(vi + 2) <- z;
132 skip2 12
134 | 0x68 when a = 6 ->
135 app c pos index 12 3 (fun pi vi ->
136 let x = rfloat (pi + 0) in
137 let y = rfloat (pi + 4) in
138 let z = rfloat (pi + 8) in
139 let _ = x,y,z in
140 if false then
141 printf "% f, % f, % f -> %f@." x y z (sqrt (x*.x +. y*.y +. z*.z));
143 skip2 12
145 | 0x6c when a = 0 -> skip (pos + 16*c)
146 | 0x6c ->
147 app c pos index 16 1 (fun pi index ->
148 let a = rfloat (pi + 0) in
149 let b = rfloat (pi + 4) in
150 let c = rfloat (pi + 8) in
151 let d = Xff.rint sbuf (pi + 12) in
152 if a < 0.0 || b < 0.0 || c < 0.0
153 then
154 printf "%d: % f, % f, % f : %d@." index a b c d
156 geom.skin.(index) <- (a,b,c,d);
158 skip2 16
160 | 0x6d when a = 2 ->
161 app c pos index 8 3 (fun pi vi ->
162 let x = r16s (pi + 0) in
163 let y = r16s (pi + 2) in
164 let z = r16s (pi + 4) in
165 geom.normala.(vi + 0) <- float x /. 4096.;
166 geom.normala.(vi + 1) <- float y /. 4096.;
167 geom.normala.(vi + 2) <- float z /. 4096.;
169 skip2 8
171 | 0x6d when a = 3 ->
172 app c pos index 8 1 (fun pi vi ->
173 let a = r16s (pi + 0) in
174 let b = r16s (pi + 2) in
175 let c = r16s (pi + 4) in
176 let d = r16s (pi + 6) in
177 let i = float a /. 4096. in
178 let j = float b /. 4096. in
179 let k = float c /. 4096. in
180 let s = float d /. 4096. in
181 let _ = i,j,k,s in ()
183 skip2 8
185 | 0x6d ->
186 skip2 8
188 | 0x6e ->
189 Xff.sbufblt sbuf
190 ~dst:geom.colora
191 ~src_pos:pos
192 ~dst_pos:(index*4)
193 ~len:(c*4)
195 skip2 4
197 | 0x00 when a = 0 && b = 0 && c = 0 ->
198 index + prev_count, counts
200 | _ ->
201 let msg = sprintf "geom (a=%x b=%x c=%x d=%x)" a b c d in
202 Xff.sbuferr sbuf pos msg
204 and r counts index prev_count pos =
205 if pos = surf1.size
206 then index + prev_count, counts
207 else r1 counts index prev_count pos
209 r [] start_index 0 12
212 let rtext n sectbuf sbuf =
213 if not (Xff.cmp sbuf (`chars "TEX\000"))
214 then
215 Xff.sbuferr sbuf 0 "invalid TEX signature"
217 let int5 = Array.init 5 (fun n -> Xff.r32 sbuf (4+n*4)) in
218 let half2_1 = Array.init 2 (fun n -> Xff.r16 sbuf (24+n*2)) in
219 let w = Xff.r16 sbuf 28
220 and h = Xff.r16 sbuf 30 in
221 let nameoff = int5.(0) in
222 let name = (Xff.rcstrtabent sectbuf (Int32.to_int nameoff) 0) in
223 let nto =
224 let xff, sbuf =
225 if true then Xff.test2 (name ^ ".nto")
226 else Xff.test2 ("scee_logo_uk.nto")
228 let dim = (w, h) in
229 Nto.r xff sbuf ~dim ()
231 { texname = name
232 ; nto = nto
233 ; int5 = int5
234 ; half1 = half2_1
235 ; w = w
236 ; h = h
240 let rsrf n sectbuf sbuf =
241 if not (Xff.cmp sbuf (`chars "SRF\000"))
242 then
243 Xff.sbuferr sbuf 0 "invalid SRF signature"
245 let tricount = Xff.rint sbuf 4
246 and stripcount = Xff.rint sbuf 8
247 and nameoff = Xff.rint sbuf 12 in
248 let hdr1 =
249 Array.init 3
250 (fun n ->
251 let sbuf = Xff.sbufplus sbuf (16 + n*16) in
252 let _0 = Array.init 4 (fun n -> Xff.r8 sbuf n) in
253 let _1 = Xff.rfloat sbuf 4 in
254 let _2 = Xff.r32 sbuf 8 in
255 let _3 = Xff.r32 sbuf 12 in
256 (_0, _1, _2, _3)
259 let hdr2 =
260 let sbuf = Xff.sbufplus sbuf (16 + 3*16) in
261 let _0 = Xff.r32 sbuf 0 in
262 let _1 = Xff.rfloat sbuf 4 in
263 let _2 = Xff.rfloat sbuf 8 in
264 let _3 = Array.init 5 (fun n -> Xff.r32 sbuf (12 + n*4)) in
265 (_0, _1, _2, _3)
267 let hdr3 =
268 let sbuf = Xff.sbufplus sbuf (16 + 3*16 + 32) in
269 Array.init 48 (fun n -> Xff.r32 sbuf (n*4))
271 let name = Xff.rcstrtabent sectbuf nameoff 0 in
272 { tricount = tricount
273 ; strcount = stripcount
274 ; name = name
275 ; hdr1 = hdr1
276 ; hdr2 = hdr2
277 ; hdr3 = hdr3
281 let r xff sbufxff =
282 if Array.length xff.Xff.sections != 2
283 then
284 Xff.sbuferr sbufxff 0 "number of xff sections is not 2"
286 let sectpos = xff.Xff.sections.(1).Xff.off in
287 let sectbuf = Xff.sbufplus sbufxff sectpos in
288 let nmobuf = Xff.sbufplus sectbuf xff.Xff.entry in
289 if not (Xff.cmp nmobuf (`chars "NMO\000"))
290 then
291 Xff.sbuferr nmobuf 0 "invalid NMO signature"
293 let hdrs = Array.init 5 (fun n ->
294 let pos = 0x30 + n*16 in
295 let off = Xff.rint nmobuf pos
296 and count = Xff.rint nmobuf (pos+4) in
297 { off = off
298 ; count = count
302 let texts =
303 Array.init hdrs.(1).count (fun n ->
304 let sbuf = Xff.sbufplus sectbuf (hdrs.(1).off + (n*32)) in
305 rtext n sectbuf sbuf
309 let surfs =
310 Array.init hdrs.(2).count (fun n ->
311 let sbuf = Xff.sbufplus sectbuf (hdrs.(2).off + (n*288)) in
312 rsrf n sectbuf sbuf
316 let num_vertices, num_strips =
317 let rec calc num_vertices n =
318 if n = hdrs.(3).count then num_vertices
319 else
320 let sbuf = Xff.sbufplus sectbuf (hdrs.(3).off + (n*32)) in
321 let surf1 = rsurf1 sbuf in
322 let here_verts = verts_in_surf1 surf1 sectbuf in
323 calc (num_vertices + here_verts) (n + 1)
325 let num_vertices = calc 0 0 in
326 let num_strips =
327 Array.fold_left
328 (fun num_strips surf -> num_strips + surf.strcount) 0 surfs
330 (num_vertices, num_strips)
333 let surf1s = Array.init hdrs.(3).count (fun n ->
334 let sbuf = Xff.sbufplus sectbuf (hdrs.(3).off + (n*32)) in
335 rsurf1 sbuf
339 let texts =
340 Array.map
341 (fun text ->
342 lazy
344 let nto = text.nto in
345 let id = GlTex.gen_texture () in
346 GlTex.bind_texture `texture_2d id;
347 GlTex.parameter `texture_2d (`mag_filter `linear);
348 if !Rend.mipmaps then (
349 GlTex.parameter `texture_2d (`min_filter `linear_mipmap_linear);
350 GlTex.parameter `texture_2d (`generate_mipmap true);
352 else (
353 GlTex.parameter `texture_2d (`min_filter `linear);
355 GlTex.parameter `texture_2d (`wrap_s `repeat);
356 GlTex.parameter `texture_2d (`wrap_t `repeat);
357 let image2d level (w, h, data) =
358 let raw = Raw.of_string data `ubyte in
359 let pix = GlPix.of_raw raw `rgba w h in
360 GlTex.image2d ~level pix
362 if !Rend.mipmaps then Array.iteri image2d nto else image2d 0 nto.(0);
365 ) texts
368 let geom =
369 { vertexa = Array.make (num_vertices*3) 0.0
370 ; normala = Array.create (num_vertices*3) 0.0
371 ; colora = String.create (num_vertices*4)
372 ; uva = Array.make (num_vertices*2) 0.0
373 ; skin = Array.create num_vertices (0., 0., 0., 0)
374 ; surfaces = []
377 let _, surfaces =
378 Array.fold_left
379 (fun (last_index, countss) surf1 ->
380 let index, counts = rgeom1 last_index surf1 geom sectbuf in
381 let surf = surfs.(surf1.surf) in
382 let _, _, _, texindex = surf.hdr1.(1) in
383 let text = texts.(Int32.to_int texindex) in
384 (index, (List.rev counts, surf, text) :: countss)
385 ) (0, []) surf1s
387 { geom with surfaces = List.rev surfaces }
390 let draw geom =
391 let l = lazy
393 let use_vbo =
394 !Rend.try_vbo && GlMisc.check_extension "GL_ARB_vertex_buffer_object"
396 Skin.init
397 use_vbo
398 (geom.vertexa, geom.normala, geom.uva, geom.skin, geom.colora)
401 fun ~textures ~lighting ~solid ~colormaterial () ->
402 let () = Lazy.force l in
403 if true then (
404 if textures then (
405 Gl.enable `texture_2d;
407 else (
408 GlDraw.line_width 1.0;
409 GlDraw.color (1., 1., 1.);
411 if colormaterial then (
412 let a = Rend.view.Rend.ambient
413 and d = Rend.view.Rend.diffuse in
414 GlLight.light 0 (`ambient (a,a,a,1.));
415 GlLight.light 0 (`diffuse (d,d,d,1.));
416 Gl.enable `color_material;
418 else (
419 GlLight.light 0 (`ambient (let c = 0.0 in (c,c,c,1.)));
420 GlLight.light 0 (`diffuse (let c = 1.0 in (c,c,c,1.)));
421 GlLight.material `both (`ambient (0.2, 0.2, 0.2, 1.0));
422 GlLight.material `both (`diffuse (0.8, 0.8, 0.8, 1.0));
424 if lighting then (
425 Gl.enable `lighting;
426 Gl.enable `light0;
427 Gl.enable `normalize;
428 GlTex.env (`mode `modulate);
429 GlLight.light_model (`two_side false);
431 else (
432 GlTex.env (`mode `replace);
434 GlDraw.polygon_mode `both (if solid then `fill else `line);
436 let rec f last_index surf = function
437 | [] -> last_index
438 | count :: rest ->
439 GlArray.draw_arrays `triangle_strip last_index count;
440 f (last_index + count) surf rest
441 and g last_index = function
442 | [] -> ()
443 | (counts, surf, id) :: rest ->
444 let texid = Lazy.force id in
445 GlTex.bind_texture `texture_2d texid;
446 let last_index = f last_index surf counts in
447 g last_index rest
450 Skin.draw_begin ();
452 g 0 geom.surfaces;
454 Skin.draw_end ();
456 Gl.disable `texture_2d;
457 Gl.disable `lighting;
458 Gl.disable `light0;
459 Gl.disable `color_material;
463 let obj geom =
464 let draw = draw geom in
465 let onoff c s b = c, "toggle " ^ s, if b then "on" else "off" in
466 (object (self)
467 val dodraw = true
468 val textures = false
469 val lighting = false
470 val solid = true
471 val colormaterial = false
473 method help =
474 [onoff "t""textures" textures
475 ;onoff "l" "lighting" lighting
476 ;onoff "w" "wireframe" (not solid)
477 ;onoff "c" "color material" colormaterial
478 ;onoff "m" "model" dodraw
481 method draw =
482 if dodraw
483 then
484 draw ~textures ~lighting ~solid ~colormaterial ()
486 method char c =
487 match c with
488 | 't' -> {< textures = not textures >}
489 | 'l' -> {< lighting = not lighting >}
490 | 'w' -> {< solid = not solid >}
491 | 'c' -> {< colormaterial = not colormaterial >}
492 | 'm' -> {< dodraw = not dodraw >}
493 | _ -> self
494 end)
497 let _ =
498 let name =
499 match !Rend.nmo_name with
500 | None -> failwith "must supply model name"
501 | Some s -> Filename.basename s
503 let x, sbuf = Xff.test2 name in
504 let geom = r x sbuf in
505 let minmax =
506 let rec f ((minx, maxx, miny, maxy, minz, maxz) as minmax) i =
507 if i >= Array.length geom.vertexa then minmax
508 else
509 let x = geom.vertexa.(i+0) in
510 let y = geom.vertexa.(i+1) in
511 let z = geom.vertexa.(i+2) in
512 let minmax =
513 min minx x, max maxx x,
514 min miny y, max maxy y,
515 min minz z, max maxz z
517 f minmax (i + 3)
519 let x = geom.vertexa.(0) in
520 let y = geom.vertexa.(1) in
521 let z = geom.vertexa.(2) in
522 f (x, x, y, y, z, z) 3
524 Skb.main name;
525 Rend.add_obj (obj geom);
526 Rend.init minmax;
527 Rend.main ()