Cosmetics
[dormin.git] / nmo.ml
blob37f1846389649f707191a3cea8979cb77828f0ed
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); *)
351 let module M =
352 struct
353 external genmipmaps:unit -> unit = "ml_set_generate_mipmaps"
355 in M.genmipmaps ()
357 else (
358 GlTex.parameter `texture_2d (`min_filter `linear);
360 GlTex.parameter `texture_2d (`wrap_s `repeat);
361 GlTex.parameter `texture_2d (`wrap_t `repeat);
362 let image2d level (w, h, data) =
363 let raw = Raw.of_string data `ubyte in
364 let pix = GlPix.of_raw raw `rgba w h in
365 GlTex.image2d ~level pix
367 if !Rend.mipmaps then Array.iteri image2d nto else image2d 0 nto.(0);
370 ) texts
373 let geom =
374 { vertexa = Array.make (num_vertices*3) 0.0
375 ; normala = Array.create (num_vertices*3) 0.0
376 ; colora = String.create (num_vertices*4)
377 ; uva = Array.make (num_vertices*2) 0.0
378 ; skin = Array.create num_vertices (0., 0., 0., 0)
379 ; surfaces = []
382 let _, surfaces =
383 Array.fold_left
384 (fun (last_index, countss) surf1 ->
385 let index, counts = rgeom1 last_index surf1 geom sectbuf in
386 let surf = surfs.(surf1.surf) in
387 let _, _, _, texindex = surf.hdr1.(1) in
388 let text = texts.(Int32.to_int texindex) in
389 (index, (List.rev counts, surf, text) :: countss)
390 ) (0, []) surf1s
392 { geom with surfaces = List.rev surfaces }
395 let draw geom =
396 let l = lazy
398 let use_vbo =
399 !Rend.try_vbo && Glut.extensionSupported "GL_ARB_vertex_buffer_object"
401 Skin.init
402 use_vbo
403 (geom.vertexa, geom.normala, geom.uva, geom.skin, geom.colora)
406 fun ~textures ~lighting ~solid ~colormaterial () ->
407 let () = Lazy.force l in
408 if true then (
409 if textures then (
410 Gl.enable `texture_2d;
412 else (
413 GlDraw.line_width 1.0;
414 GlDraw.color (1., 1., 1.);
416 if colormaterial then (
417 let a = Rend.view.Rend.ambient
418 and d = Rend.view.Rend.diffuse in
419 GlLight.light 0 (`ambient (a,a,a,1.));
420 GlLight.light 0 (`diffuse (d,d,d,1.));
421 Gl.enable `color_material;
423 else (
424 GlLight.light 0 (`ambient (let c = 0.0 in (c,c,c,1.)));
425 GlLight.light 0 (`diffuse (let c = 1.0 in (c,c,c,1.)));
426 GlLight.material `both (`ambient (0.2, 0.2, 0.2, 1.0));
427 GlLight.material `both (`diffuse (0.8, 0.8, 0.8, 1.0));
429 if lighting then (
430 Gl.enable `lighting;
431 Gl.enable `light0;
432 Gl.enable `normalize;
433 GlTex.env (`mode `modulate);
434 GlLight.light_model (`two_side false);
436 else (
437 GlTex.env (`mode `replace);
439 GlDraw.polygon_mode `both (if solid then `fill else `line);
441 let rec f last_index surf = function
442 | [] -> last_index
443 | count :: rest ->
444 GlArray.draw_arrays `triangle_strip last_index count;
445 f (last_index + count) surf rest
446 and g last_index = function
447 | [] -> ()
448 | (counts, surf, id) :: rest ->
449 let texid = Lazy.force id in
450 GlTex.bind_texture `texture_2d texid;
451 let last_index = f last_index surf counts in
452 g last_index rest
455 Skin.draw_begin ();
457 g 0 geom.surfaces;
459 Skin.draw_end ();
461 Gl.disable `texture_2d;
462 Gl.disable `lighting;
463 Gl.disable `light0;
464 Gl.disable `color_material;
468 let obj geom =
469 let draw = draw geom in
470 let onoff c s b = c, "toggle " ^ s, if b then "on" else "off" in
471 (object (self)
472 val dodraw = true
473 val textures = false
474 val lighting = false
475 val solid = true
476 val colormaterial = false
478 method help =
479 [onoff "t" "textures" textures
480 ;onoff "l" "lighting" lighting
481 ;onoff "w" "wireframe" (not solid)
482 ;onoff "c" "color material" colormaterial
483 ;onoff "m" "model" dodraw
486 method draw =
487 if dodraw
488 then
489 draw ~textures ~lighting ~solid ~colormaterial ()
491 method char c =
492 match c with
493 | 't' -> {< textures = not textures >}
494 | 'l' -> {< lighting = not lighting >}
495 | 'w' -> {< solid = not solid >}
496 | 'c' -> {< colormaterial = not colormaterial >}
497 | 'm' -> {< dodraw = not dodraw >}
498 | _ -> self
499 end)
502 let _ =
503 let name =
504 match !Rend.nmo_name with
505 | None -> failwith "must supply model name"
506 | Some s -> Filename.basename s
508 let x, sbuf = Xff.test2 name in
509 let geom = r x sbuf in
510 let minmax =
511 let rec f ((minx, maxx, miny, maxy, minz, maxz) as minmax) i =
512 if i >= Array.length geom.vertexa
513 then minmax
514 else
515 let x = geom.vertexa.(i+0) in
516 let y = geom.vertexa.(i+1) in
517 let z = geom.vertexa.(i+2) in
518 let minmax =
519 min minx x, max maxx x,
520 min miny y, max maxy y,
521 min minz z, max maxz z
523 f minmax (i + 3)
525 let x = geom.vertexa.(0) in
526 let y = geom.vertexa.(1) in
527 let z = geom.vertexa.(2) in
528 f (x, x, y, y, z, z) 3
530 Skb.main name;
531 Rend.add_obj (obj geom);
532 Rend.init minmax;
533 Rend.main ()