From 7e21ab2ed65dc74682601dba2ca25644bb355617 Mon Sep 17 00:00:00 2001 From: malc Date: Mon, 17 Nov 2008 07:26:22 +0300 Subject: [PATCH] Hardware skinning --- build.ml | 24 ++-- do.bat | 2 +- do.sh | 6 +- pgl.h | 27 ++++- rend.ml | 21 ++-- skin.ml | 68 +++++++++++ skin.vp | 74 ++++++++++++ skinvp.c | 403 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ vec.c | 91 +++++++++------ 9 files changed, 657 insertions(+), 59 deletions(-) create mode 100644 skin.vp create mode 100644 skinvp.c diff --git a/build.ml b/build.ml index 58c12f9..e4013ae 100644 --- a/build.ml +++ b/build.ml @@ -29,23 +29,25 @@ let boc flags src = (StrSet.singleton o) [Filename.concat srcdir c] ( - if src = "skin" - then StrSet.singleton (Filename.concat srcdir "vec.c") + if src = "skin" || src = "skinvp" + then StrSet.add "progvp1.h" + (StrSet.add (Filename.concat srcdir "pgl.h") + (StrSet.singleton (Filename.concat srcdir "vec.c"))) else StrSet.empty ) ; ;; -let bso src = - let so = src ^ ".so" in +let bso name objs = + let so = name ^ ".so" in let so = Filename.concat (Sys.getcwd ()) so in - let o = src ^ ".o" in + let o = List.map (fun s -> s ^ ".o") objs in ocaml cc ("-shared -o " ^ so) so (StrSet.singleton so) - [o] + o StrSet.empty ; so @@ -58,8 +60,9 @@ let _ = ; boc "-g" "swizzle"; boc "-g" "skin"; - let so = bso "swizzle" in - let so1 = bso "skin" in + boc "-g" "skinvp"; + let so = bso "swizzle" ["swizzle"] in + let so1 = bso "skin" ["skin"; "skinvp"] in let prog name cmos = ocaml "ocamlc.opt" @@ -69,9 +72,8 @@ let _ = (State.dep_sort cmos) StrSet.empty in - prog "dormin" ["slice.cmo"; "xff.cmo"; "nto.cmo"; "rend.cmo"; - "vec.cmo"; "anb.cmo"; "skb.cmo"; "skin.cmo"; - "nmo.cmo"; "qtr.cmo"; + prog "dormin" ["slice.cmo"; "xff.cmo"; "nto.cmo"; "skin.cmo"; "rend.cmo"; + "vec.cmo"; "anb.cmo"; "skb.cmo"; "nmo.cmo"; "qtr.cmo"; so; so1]; () ;; diff --git a/do.bat b/do.bat index 71434d7..40802a6 100644 --- a/do.bat +++ b/do.bat @@ -1 +1 @@ -ocamlc -ccopt -O2 -o dormin -custom -I +lablGL unix.cma lablgl.cma lablglut.cma skin.c swizzle.c slice.ml vec.ml qtr.ml xff.ml rend.ml skin.ml anb.ml skb.ml nto.ml nmo.ml +ocamlc -ccopt -O2 -o dormin -custom -I +lablGL unix.cma lablgl.cma lablglut.cma skin.c skinvp.c swizzle.c slice.ml vec.ml qtr.ml xff.ml skin.ml rend.ml anb.ml skb.ml nto.ml nmo.ml diff --git a/do.sh b/do.sh index 1ebbab6..39615a3 100644 --- a/do.sh +++ b/do.sh @@ -1,9 +1,9 @@ ocamlc -ccopt -O -o dormin -custom -I +lablGL unix.cma lablgl.cma lablglut.cma \ - skin.c swizzle.c \ - slice.ml vec.ml qtr.ml xff.ml rend.ml skin.ml anb.ml skb.ml nto.ml nmo.ml + skin.c skinvp.c swizzle.c \ + slice.ml vec.ml qtr.ml xff.ml skin.ml rend.ml anb.ml skb.ml nto.ml nmo.ml #mv skin.o skin1.o #mv swizzle.o swizzle1.o #ocamlopt.opt -o dormin.opt -I +lablGL unix.cmxa lablgl.cmxa lablglut.cmxa \ # slice.ml vec.ml qtr.ml xff.ml rend.ml skin.ml anb.ml skb.ml nto.ml nmo.ml \ -# skin1.o swizzle1.o +# skin1.o swizzle1.o skinvp.o diff --git a/pgl.h b/pgl.h index 4b1817f..2f32bd4 100644 --- a/pgl.h +++ b/pgl.h @@ -29,6 +29,32 @@ static PFNGLGENBUFFERSPROC glGenBuffers; static PFNGLBUFFERDATAPROC glBufferData; static PFNGLMAPBUFFERPROC glMapBuffer; static PFNGLUNMAPBUFFERPROC glUnmapBuffer; +#endif + +#ifndef GL_ARB_vertex_program +#define GL_VERTEX_PROGRAM_ARB 0x8620 +#define GL_PROGRAM_STRING_ARB 0x8628 +#define GL_VERTEX_ATTRIB_ARRAY_POINTER_ARB 0x8645 +#define GL_PROGRAM_ERROR_POSITION_ARB 0x864B +#define GL_PROGRAM_ERROR_STRING_ARB 0x8874 +#define GL_PROGRAM_FORMAT_ASCII_ARB 0x8875 +#define GL_PROGRAM_FORMAT_ARB 0x8876 +#define GL_PROGRAM_ATTRIBS_ARB 0x88AC +#define GL_MAX_PROGRAM_ATTRIBS_ARB 0x88AD +typedef void (APIENTRYP PFNGLPROGRAMSTRINGARBPROC) (GLenum target, GLenum format, GLsizei len, const GLvoid *string); +typedef void (APIENTRYP PFNGLBINDPROGRAMARBPROC) (GLenum target, GLuint program); +typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETER4FVARBPROC) (GLenum target, GLuint index, const GLfloat *params); +typedef void (APIENTRYP PFNGLENABLEVERTEXATTRIBARRAYARBPROC) (GLuint index); +typedef void (APIENTRYP PFNGLDISABLEVERTEXATTRIBARRAYARBPROC) (GLuint index); +typedef void (APIENTRYP PFNGLVERTEXATTRIBPOINTERARBPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid *pointer); +static PFNGLBINDPROGRAMARBPROC glBindProgramARB; +static PFNGLPROGRAMSTRINGARBPROC glProgramStringARB; +static PFNGLPROGRAMLOCALPARAMETER4FVARBPROC glProgramLocalParameter4fvARB; +static PFNGLENABLEVERTEXATTRIBARRAYARBPROC glEnableVertexAttribArrayARB; +static PFNGLENABLEVERTEXATTRIBARRAYARBPROC glDisableVertexAttribArrayARB; +static PFNGLVERTEXATTRIBPOINTERARBPROC glVertexAttribPointerARB; +#endif + #define GETPA(name) for (;;) { \ *(PROC *) &gl##name = wglGetProcAddress ("gl" # name); \ if (!gl##name) { \ @@ -37,4 +63,3 @@ static PFNGLUNMAPBUFFERPROC glUnmapBuffer; } \ break; \ } -#endif diff --git a/rend.ml b/rend.ml index b15fd88..6dc0f69 100644 --- a/rend.ml +++ b/rend.ml @@ -8,6 +8,7 @@ let try_vbo = ref true let nmo_name = ref None let anb_names = ref [] let skb_name = ref None +let vp_name = ref "" let mipmaps = ref false let slerp_step = ref 1.0 @@ -386,14 +387,6 @@ let mouse ~button ~state ~x ~y = ;; let main () = - let w = 704 - and h = 576 in - let _ = Glut.init Sys.argv in - let () = Glut.initDisplayMode ~depth:true ~double_buffer:true () in - let () = Glut.initWindowSize w h in - let _ = Glut.createWindow "rend (press 'h' to get help)" in - Gl.enable `depth_test; - Gl.enable `alpha_test; let () = Glut.displayFunc display in let () = Glut.reshapeFunc reshape in let () = Glut.keyboardFunc keyboard in @@ -416,6 +409,14 @@ let init minmax = ;; let _ = + let w = 704 + and h = 576 in + let _ = Glut.init Sys.argv in + let () = Glut.initDisplayMode ~depth:true ~double_buffer:true () in + let () = Glut.initWindowSize w h in + let _ = Glut.createWindow "rend (press 'h' to get help)" in + Gl.enable `depth_test; + Gl.enable `alpha_test; let setsome r s = r := Some s in let spec = ["-slice", Arg.String Slice.openslice, " of file/dir to slice data to" @@ -426,6 +427,7 @@ let _ = ;("-skb", Arg.String (setsome skb_name), " use specified skb instead of guessing") ;"-mipmaps", Arg.Set mipmaps, " use mipmaps" + ;"-vp", Arg.Set_string vp_name, " vertex program" ] in Arg.parse (Arg.align spec) @@ -434,5 +436,6 @@ let _ = then anb_names := s :: !anb_names else nmo_name := Some s; ) - "Usage: dormin [options] model.nmo [animation.anb ...]" + "Usage: dormin [options] model.nmo [animation.anb ...]"; + Skin.set !vp_name; ;; diff --git a/skin.ml b/skin.ml index 6546a43..cfd1e77 100644 --- a/skin.ml +++ b/skin.ml @@ -5,6 +5,7 @@ type vertices = float array type normals = float array type coords = float array +module SW = struct external init : bool -> (vertices * normals * coords * skin * string) -> unit = "ml_skin_init" @@ -14,3 +15,70 @@ external draw_end : unit -> unit = "ml_skin_draw_end" external set_skel : skel -> unit = "ml_skin_set_skel" external set_anim : anim -> unit = "ml_skin_set_anim" external anim : unit -> unit = "ml_skin_anim" +end + +module HW = struct +external init : + string -> bool -> (vertices * normals * coords * skin * string) -> unit + = "ml_skin_init_vp" + +external draw_begin : unit -> unit = "ml_skin_draw_begin_vp" +external draw_end : unit -> unit = "ml_skin_draw_end_vp" + +external set_skel : skel -> unit = "ml_skin_set_skel_vp" +external set_anim : anim -> unit = "ml_skin_set_anim_vp" +external anim : unit -> unit = "ml_skin_anim_vp" +end + +let sw = object (self) + method init = SW.init + method draw_begin = SW.draw_begin + method draw_end = SW.draw_end + method set_skel = SW.set_skel + method set_anim = SW.set_anim + method anim = SW.anim +end;; + +let hw prog = object (self) + method init = HW.init prog + method draw_begin = HW.draw_begin + method draw_end = HW.draw_end + method set_skel = HW.set_skel + method set_anim = HW.set_anim + method anim = HW.anim +end;; + +let skin = ref sw;; + +let set path = + if String.length path = 0 + then skin := sw + else ( + if Glut.extensionSupported "GL_ARB_vertex_program" + then + let prog = + let ic = open_in path in + let b = Buffer.create 100 in + begin try + while true do + Buffer.add_string b (input_line ic); + Buffer.add_char b '\n'; + done + with End_of_file -> () + end; + Buffer.contents b + in + skin := hw prog + else ( + Format.eprintf "GL_ARB_vertex_program not supported falling back to sw@."; + skin := sw + ) + ) +;; + +let init a = !skin#init a;; +let draw_begin a = !skin#draw_begin a;; +let draw_end a = !skin#draw_end a;; +let set_skel a = !skin#set_skel a;; +let set_anim a = !skin#set_anim a;; +let anim a = !skin#anim a;; diff --git a/skin.vp b/skin.vp new file mode 100644 index 0000000..c88982a --- /dev/null +++ b/skin.vp @@ -0,0 +1,74 @@ +!!ARBvp1.0 + +PARAM c4 = {4, 0, 20, 1}; +PARAM mvp[4] = { state.matrix.mvp }; +PARAM anim[] = { program.local[0..121] }; + +ATTRIB position = vertex.attrib[0]; +ATTRIB normal = vertex.attrib[2]; +ATTRIB color = vertex.attrib[3]; +ATTRIB weights = vertex.attrib[6]; +ATTRIB texcoord = vertex.attrib[8]; + +TEMP v, v2, v1, r0, r1, r2, t0, w; +ADDRESS a0; + +####################################################################### +FRC w, weights; +FLR t0, weights; + +ARL a0.x, t0.x; + +MUL r0, anim[a0.x+0], w.x; +MUL r1, anim[a0.x+1], w.x; +MUL r2, anim[a0.x+2], w.x; +SUB v1.xyz, position, anim[a0.x+3]; + +DPH v.x, v1, r0; +DPH v.y, v1, r1; +DPH v.z, v1, r2; + +############################## +ARL a0.x, t0.y; + +MUL r0, anim[a0.x+0], w.y; +MUL r1, anim[a0.x+1], w.y; +MUL r2, anim[a0.x+2], w.y; +SUB v1.xyz, position, anim[a0.x+3]; + +DPH v2.x, v1, r0; +DPH v2.y, v1, r1; +DPH v2.z, v1, r2; + +MAD v.xyz, anim[a0.x+3].w, v2, v; + +############################## +ARL a0.x, t0.z; + +MUL r0, anim[a0.x+0], w.z; +MUL r1, anim[a0.x+1], w.z; +MUL r2, anim[a0.x+2], w.z; +SUB v1.xyz, position, anim[a0.x+3]; + +DPH v2.x, v1, r0; +DPH v2.y, v1, r1; +DPH v2.z, v1, r2; + +MAD v.xyz, anim[a0.x+3].w, v2, v; + +MOV v.w, c4.w; +###################################################################### +#MOV v, position; +DP4 result.position.x, mvp[0], v; +DP4 result.position.y, mvp[1], v; +DP4 result.position.z, mvp[2], v; +DP4 result.position.w, mvp[3], v; + +MOV result.color, color; +MOV result.texcoord, texcoord; + +END + +# Local Variables: +# mode: python +# End: diff --git a/skinvp.c b/skinvp.c new file mode 100644 index 0000000..05527dc --- /dev/null +++ b/skinvp.c @@ -0,0 +1,403 @@ +#include +#include +#include +#include + +#include +#include +#include + +#define USE_VP + +#include "vec.c" +#include "pgl.h" + +#ifdef _MSC_VER +#define snprintf _snprintf +#endif + +enum {V_IDX, N_IDX, UV_IDX, C_IDX, A_IDX, COUNT}; + +struct skin { + int boneindices[3]; + float weights[3]; + int num_bones; +}; + +struct bone { + int parent; + + float v[4]; + float q[4]; + + float mv[4]; + float mq[4]; + + float aq[4]; + float amq[4]; + float amv[4]; + + float cm[16]; +}; + +struct adescr { + int size; + int norm; + int index; + int stride; + int offset; + int num_elems; + GLenum type; +}; + +const struct adescr ad[] = { + { 4, 0, 0, 12, 0, 3, GL_FLOAT }, + { 4, 0, 2, 12, 0, 3, GL_FLOAT }, + { 4, 0, 8, 8, 0, 2, GL_FLOAT }, + { 1, 1, 3, 4, 0, 4, GL_UNSIGNED_BYTE }, + { 4, 0, 6, 12, 0, 3, GL_FLOAT } +}; + +typedef struct { + char *array; + int num_bones; + int num_vertices; + GLuint bufid; + struct adescr ad[COUNT]; + struct skin *skin; + struct bone *bones; +} State; + +static State glob_state; +static int use_vbo; + +static void skin_init (State *s, value vertexa_v, value normala_v, + value uva_v, value skin_v, value colors_v, + int interleave) +{ + int i; + char *p; + char *map; + GLsizei size; + struct skin *skin; + GLsizei offset = 0; + GLsizei stride = 12 * sizeof (GLfloat); + GLsizei strides[COUNT]; + + s->num_vertices = Wosize_val (vertexa_v) / (Double_wosize * 3); + + for (i = 0, size = 0; i < COUNT; ++i) { + s->ad[i].index = ad[i].index; + if (interleave) { + s->ad[i].offset = offset; + s->ad[i].stride = stride; + strides[i] = stride; + offset += ad[i].stride; + } + else { + strides[i] = ad[i].stride; + s->ad[i].offset = size; + s->ad[i].stride = + ad[i].num_elems*ad[i].size == ad[i].stride + ? 0 + : ad[i].stride + ; + } + s->ad[i].norm = ad[i].norm; + s->ad[i].type = ad[i].type; + s->ad[i].num_elems = ad[i].num_elems; + s->ad[i].size = ad[i].num_elems * ad[i].size * s->num_vertices; + size += s->ad[i].size; + } + + if (use_vbo) { + glGenBuffers (1, &s->bufid); + glBindBuffer (GL_ARRAY_BUFFER, s->bufid); + glBufferData (GL_ARRAY_BUFFER, size, NULL, GL_STATIC_DRAW); + map = glMapBuffer (GL_ARRAY_BUFFER, GL_WRITE_ONLY); + if (!map) caml_failwith ("glMapBuffer failed"); + } + else { + map = stat_alloc (size); + } + + p = map + s->ad[V_IDX].offset; + for (i = 0; i < s->num_vertices; ++i) { + ((float *) p)[0] = Double_field (vertexa_v, i*3 + 0); + ((float *) p)[1] = Double_field (vertexa_v, i*3 + 1); + ((float *) p)[2] = Double_field (vertexa_v, i*3 + 2); + p += strides[V_IDX]; + } + + p = map + s->ad[N_IDX].offset; + for (i = 0; i < s->num_vertices; ++i) { + ((float *) p)[0] = Double_field (normala_v, i*3 + 0); + ((float *) p)[1] = Double_field (normala_v, i*3 + 1); + ((float *) p)[2] = Double_field (normala_v, i*3 + 2); + p += strides[N_IDX]; + } + + p = map + s->ad[UV_IDX].offset; + for (i = 0; i < s->num_vertices; ++i) { + ((float *) p)[0] = Double_field (uva_v, i*2 + 0); + ((float *) p)[1] = Double_field (uva_v, i*2 + 1); + p += strides[UV_IDX]; + } + + p = map + s->ad[C_IDX].offset; + + for (i = 0; i < s->num_vertices; ++i) { + memcpy (p, String_val (colors_v) + i*4, 4); + p += strides[C_IDX]; + } + + s->skin = skin = stat_alloc (s->num_vertices * sizeof (struct skin)); + p = map + s->ad[A_IDX].offset; + + for (i = 0; i < s->num_vertices; ++i) { + int j; + value v; + + v = Field (skin_v, i); + skin[i].num_bones = Int_val (Field (v, 3)); + + for (j = 0; j < skin[i].num_bones; ++j) { + double val, w; + + val = Double_val (Bp_val (Field (v, j))); + skin[i].boneindices[j] = (int) val; + w = val - skin[i].boneindices[j]; + skin[i].weights[j] = w; + skin[i].boneindices[j] += 1; + ((float *) p)[j] = skin[i].boneindices[j] * 4 + w; + } + + for (j = skin[i].num_bones; j < 3; ++j) { + ((float *) p)[j] = 0.0; + } + p += strides[A_IDX]; + } + + if (use_vbo) { + if (glUnmapBuffer (GL_ARRAY_BUFFER) == GL_FALSE) + caml_failwith ("glUnmapBuffer failed"); + } + else { + s->array = map; + } +} + +static void skin_anim (State *s) +{ + int i, j = 4; + struct bone *b = s->bones + 1; + + for (i = 0; i < s->num_bones; ++i, ++b, j += 4) { + glProgramLocalParameter4fvARB (GL_VERTEX_PROGRAM_ARB, j + 0, b->cm + 0); + glProgramLocalParameter4fvARB (GL_VERTEX_PROGRAM_ARB, j + 1, b->cm + 4); + glProgramLocalParameter4fvARB (GL_VERTEX_PROGRAM_ARB, j + 2, b->cm + 8); + glProgramLocalParameter4fvARB (GL_VERTEX_PROGRAM_ARB, j + 3, b->cm + 12); + } +} + +static void load_program (const char *text, GLsizei size, GLuint progid) +{ + glBindProgramARB (GL_VERTEX_PROGRAM_ARB, progid); + + glProgramStringARB (GL_VERTEX_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, + size, (const GLubyte *) text); + if (glGetError () != GL_NO_ERROR) { + GLint pos; + char buf[1024]; + + glGetIntegerv (GL_PROGRAM_ERROR_POSITION_ARB, &pos); + snprintf (buf, 1024, "glProgramStringARB: error %s at %d", + (char *) glGetString (GL_PROGRAM_ERROR_STRING_ARB), pos); + caml_failwith (buf); + } + { + float r[4]; + + memset (r, 0, sizeof (r)); + glProgramLocalParameter4fvARB (GL_VERTEX_PROGRAM_ARB, 0, r); + glProgramLocalParameter4fvARB (GL_VERTEX_PROGRAM_ARB, 0, r); + glProgramLocalParameter4fvARB (GL_VERTEX_PROGRAM_ARB, 0, r); + glProgramLocalParameter4fvARB (GL_VERTEX_PROGRAM_ARB, 0, r); + } +} + +CAMLprim value ml_skin_draw_begin_vp (value unit_v) +{ + int i; + State *s = &glob_state; + + (void) unit_v; + + glBindBuffer (GL_ARRAY_BUFFER, s->bufid); + + for (i = 0; i < COUNT; ++i) { + struct adescr *ad = &s->ad[i]; + + glEnableVertexAttribArrayARB (ad->index); + glVertexAttribPointerARB (ad->index, ad->num_elems, ad->type, + ad->norm, ad->stride, s->array + ad->offset); + } + + glEnable (GL_VERTEX_PROGRAM_ARB); + return Val_unit; +} + +CAMLprim value ml_skin_draw_end_vp (value unit_v) +{ + int i; + State *s = &glob_state; + + (void) unit_v; + + for (i = 0; i < COUNT; ++i) + glDisableVertexAttribArrayARB (s->ad[i].index); + + glBindBuffer (GL_ARRAY_BUFFER, 0); + glDisable (GL_VERTEX_PROGRAM_ARB); + return Val_unit; +} + +CAMLprim value ml_skin_init_vp (value text_v, value use_vbo_v, value geom_v) +{ + CAMLparam3 (use_vbo_v, text_v, geom_v); + CAMLlocal5 (vertexa_v, normala_v, uva_v, skin_v, colors_v); + State *s = &glob_state; + + use_vbo = Bool_val (use_vbo_v); +#ifdef _WIN32 + GETPA (BindBuffer); + GETPA (GenBuffers); + GETPA (BufferData); + GETPA (MapBuffer); + GETPA (UnmapBuffer); + GETPA (BindProgramARB); + GETPA (ProgramStringARB); + GETPA (ProgramLocalParameter4fvARB); + GETPA (EnableVertexAttribArrayARB); + GETPA (DisableVertexAttribArrayARB); + GETPA (VertexAttribPointerARB); +#endif + + vertexa_v = Field (geom_v, 0); + normala_v = Field (geom_v, 1); + uva_v = Field (geom_v, 2); + skin_v = Field (geom_v, 3); + colors_v = Field (geom_v, 4); + + skin_init (s, vertexa_v, normala_v, uva_v, skin_v, colors_v, 1); + load_program (String_val (text_v), caml_string_length (text_v), 1); + skin_anim (s); + + CAMLreturn (Val_unit); +} + +CAMLprim value ml_skin_set_skel_vp (value skel_v) +{ + int i; + size_t size; + struct bone *b; + CAMLparam1 (skel_v); + CAMLlocal2 (v, floats_v); + State *s = &glob_state; + + s->num_bones = Wosize_val (skel_v); + size = (s->num_bones + 1) * sizeof (struct bone); + s->bones = b = stat_alloc (size); + + memset (b, 0, size); + b->parent = -1; + b->q[3] = 1.0; + b->mq[3] = 1.0; + b->aq[3] = 1.0; + b->amq[3] = 1.0; + b++; + + for (i = 0; i < s->num_bones; ++i, ++b) { + v = Field (skel_v, i); + floats_v = Field (v, 1); + + b->parent = Int_val (Field (v, 0)) + 1; + + b->v[0] = Double_field (floats_v, 1); + b->v[1] = Double_field (floats_v, 2); + b->v[2] = Double_field (floats_v, 3); + + b->q[0] = Double_field (floats_v, 5); + b->q[1] = Double_field (floats_v, 6); + b->q[2] = Double_field (floats_v, 7); + b->q[3] = Double_field (floats_v, 8); + } + + b = s->bones + 1; + for (i = 0; i < s->num_bones; ++i, ++b) { + float v[3]; + struct bone *parent = &s->bones[b->parent]; + + qapply (v, parent->mq, b->v); + qcompose (b->mq, b->q, parent->mq); + vadd (b->mv, v, parent->mv); + + memset (b->cm, 0, sizeof (b->cm)); + b->cm[0] = 1.0; + b->cm[5] = 1.0; + b->cm[10] = 1.0; + b->cm[15] = 1.0; + + b->cm[3] = b->mv[0]; + b->cm[7] = b->mv[1]; + b->cm[11] = b->mv[2]; + + b->cm[12] = b->mv[0]; + b->cm[13] = b->mv[1]; + b->cm[14] = b->mv[2]; + } + + CAMLreturn (Val_unit); +} + +CAMLprim value ml_skin_set_anim_vp (value anim_v) +{ + int i; + CAMLparam1 (anim_v); + CAMLlocal1 (floats_v); + State *s = &glob_state; + struct bone *b = s->bones + 1; + + for (i = 0; i < s->num_bones; ++i, ++b) { + floats_v = Field (anim_v, i); + b->aq[0] = Double_field (floats_v, 0); + b->aq[1] = Double_field (floats_v, 1); + b->aq[2] = Double_field (floats_v, 2); + b->aq[3] = Double_field (floats_v, 3); + } + + b = s->bones + 1; + for (i = 0; i < s->num_bones; ++i, ++b) { + float v[3], q[4], q1[4]; + struct bone *parent = &s->bones[b->parent]; + + qapply (v, parent->amq, b->v); + qcompose (b->amq, b->aq, parent->amq); + vadd (b->amv, v, parent->amv); + + qconjugate (q1, b->mq); + qcompose (q, q1, b->amq); + q2matrixt (b->cm, q, b->amv); + } + + CAMLreturn (Val_unit); +} + +CAMLprim value ml_skin_anim_vp (value unit_v) +{ + CAMLparam1 (unit_v); + State *s = &glob_state; + + skin_anim (s); + CAMLreturn (Val_unit); +} diff --git a/vec.c b/vec.c index 8b01113..a8d5bca 100644 --- a/vec.c +++ b/vec.c @@ -5,13 +5,6 @@ static void vneg (float *res, float *v) res[2] = -v[2]; } -static void vcopy (float *res, float *v) -{ - *res++ = *v++; - *res++ = *v++; - *res++ = *v++; -} - static void vadd (float *res, float *v1, float *v2) { res[0] = v1[0] + v2[0]; @@ -19,24 +12,12 @@ static void vadd (float *res, float *v1, float *v2) res[2] = v1[2] + v2[2]; } -static void vsub (float *res, float *v1, float *v2) -{ - res[0] = v1[0] - v2[0]; - res[1] = v1[1] - v2[1]; - res[2] = v1[2] - v2[2]; -} - static void qconjugate (float *res, float *q) { vneg (res, q); res[3] = q[3]; } -static float qmagnitude (float *q) -{ - return sqrt (q[0]*q[0]+q[1]*q[1]+q[2]*q[2]+q[3]*q[3]); -} - static void qapply (float *res, float *q, float *v) { float a = -q[3]; @@ -61,14 +42,6 @@ static void qapply (float *res, float *q, float *v) res[2] = 2*( (t7 - t3)*v1 + (t2 + t9)*v2 + (t5 + t8)*v3 ) + v3; } -static void qscale (float *res, float *q, float scale) -{ - *res++ = *q++ * scale; - *res++ = *q++ * scale; - *res++ = *q++ * scale; - *res++ = *q++ * scale; -} - static void qcompose (float *res, float *q1, float *q2) { res[0] = q1[3]*q2[0] + q1[0]*q2[3] + q1[1]*q2[2] - q1[2]*q2[1]; @@ -77,6 +50,7 @@ static void qcompose (float *res, float *q1, float *q2) res[3] = q1[3]*q2[3] - q1[0]*q2[0] - q1[1]*q2[1] - q1[2]*q2[2]; } +#ifndef USE_VP static void q2matrixt (float *mat, float *q, float *v) { float X = q[0]; @@ -119,18 +93,12 @@ static void q2matrixt (float *mat, float *q, float *v) #endif } -static void q2matrix (float *mat, float *q) -{ - float z[3] = {0,0,0}; - q2matrixt (mat, q, z); -} - +#ifndef USE_ALTIVEC static void mscale (float *res, float *m, float s) { int i; for (i = 0; i < 12; ++i) *res++ = *m++ * s; } - static void mapply_to_point (float *res, float *m, float *v) { float x = v[0]; @@ -157,3 +125,58 @@ static void vaddto (float *v1, float *v2) v1[1] += v2[1]; v1[2] += v2[2]; } + +static void vcopy (float *res, float *v) +{ + *res++ = *v++; + *res++ = *v++; + *res++ = *v++; +} + +static void vsub (float *res, float *v1, float *v2) +{ + res[0] = v1[0] - v2[0]; + res[1] = v1[1] - v2[1]; + res[2] = v1[2] - v2[2]; +} +#endif + +#else + +static void q2matrixt (float *mat, float *q, float *v) +{ + float X = q[0]; + float Y = q[1]; + float Z = q[2]; + float W = q[3]; + + float xx = X * X; + float xy = X * Y; + float xz = X * Z; + float xw = X * W; + + float yy = Y * Y; + float yz = Y * Z; + float yw = Y * W; + + float zz = Z * Z; + float zw = Z * W; + + mat[0] = 1 - 2 * ( yy + zz ); + mat[4] = 2 * ( xy - zw ); + mat[8] = 2 * ( xz + yw ); + + mat[1] = 2 * ( xy + zw ); + mat[5] = 1 - 2 * ( xx + zz ); + mat[9] = 2 * ( yz - xw ); + + mat[2] = 2 * ( xz - yw ); + mat[6] = 2 * ( yz + xw ); + mat[10] = 1 - 2 * ( xx + yy ); + + mat[3] = v[0]; + mat[7] = v[1]; + mat[11] = v[2]; + mat[15] = 1.0; +} +#endif -- 2.11.4.GIT