Misc refactoring
[dormin.git] / skin.c
blob77afd13df804752e75cbdeae88645514a2af2ee7
1 #include <math.h>
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <string.h>
6 #include <caml/fail.h>
7 #include <caml/alloc.h>
8 #include <caml/memory.h>
10 #include "vec.c"
11 #include "pgl.h"
13 enum {V_IDX, N_IDX, UV_IDX, C_IDX, COUNT};
15 struct skin {
16 int boneindices[3];
17 float weights[3];
18 int num_bones;
21 struct bone {
22 int parent;
24 float v[4] A16;
25 float q[4] A16;
27 float mv[4] A16;
28 float mq[4];
30 float aq[4];
31 float amq[4];
32 float amv[4];
34 float am[16] A16;
35 float im[16] A16;
38 typedef struct {
39 int num_bones;
40 int num_vertices;
41 GLuint bufid[COUNT];
42 float *ptrs[COUNT];
43 struct skin *skin;
44 struct bone *bones;
45 } State;
47 static State glob_state;
49 static void skin_init (State *s, value vertexa_v, value normala_v,
50 value uva_v, value skin_v, value colors_v)
52 int i;
53 GLsizei size;
54 float *p;
55 struct skin *skin;
56 s->num_vertices = Wosize_val (vertexa_v) / (Double_wosize * 3);
58 glGenBuffers (COUNT, s->bufid);
60 size = s->num_vertices * sizeof (GLfloat) * 3;
61 p = s->ptrs[V_IDX] = stat_alloc (size);
62 for (i = 0; i < s->num_vertices * 3; ++i) {
63 p[i] = Double_field (vertexa_v, i);
65 glBindBuffer (GL_ARRAY_BUFFER, s->bufid[V_IDX]);
66 glBufferData (GL_ARRAY_BUFFER, size, p, GL_DYNAMIC_DRAW);
68 p = s->ptrs[N_IDX] = stat_alloc (size);
69 for (i = 0; i < s->num_vertices * 3; ++i) {
70 p[i] = Double_field (normala_v, i);
72 glBindBuffer (GL_ARRAY_BUFFER, s->bufid[N_IDX]);
73 glBufferData (GL_ARRAY_BUFFER, size, p, GL_DYNAMIC_DRAW);
75 size = s->num_vertices * sizeof (GLfloat) * 2;
76 p = s->ptrs[UV_IDX] = stat_alloc (size);
77 for (i = 0; i < s->num_vertices * 2; ++i) {
78 p[i] = Double_field (uva_v, i);
80 glBindBuffer (GL_ARRAY_BUFFER, s->bufid[UV_IDX]);
81 glBufferData (GL_ARRAY_BUFFER, size, p, GL_STATIC_DRAW);
82 stat_free (p);
84 size = s->num_vertices * 4;
85 glBindBuffer (GL_ARRAY_BUFFER, s->bufid[C_IDX]);
86 glBufferData (GL_ARRAY_BUFFER, size, String_val (colors_v), GL_STATIC_DRAW);
88 s->skin = skin = stat_alloc (s->num_vertices * sizeof (struct skin));
89 for (i = 0; i < s->num_vertices; ++i) {
90 int j;
91 value v;
93 v = Field (skin_v, i);
94 skin[i].num_bones = Int_val (Field (v, 3));
96 for (j = 0; j < skin[i].num_bones; ++j) {
97 double val;
99 val = Double_val (Bp_val (Field (v, j)));
100 skin[i].boneindices[j] = (int) val;
101 skin[i].weights[j] = val - skin[i].boneindices[j];
102 skin[i].boneindices[j] += 1;
107 CAMLprim value ml_skin_draw_begin (value unit_v)
109 State *s = &glob_state;
111 (void) unit_v;
112 glEnableClientState (GL_VERTEX_ARRAY);
113 glBindBuffer (GL_ARRAY_BUFFER, s->bufid[V_IDX]);
114 glVertexPointer (3, GL_FLOAT, 0, NULL);
116 glEnableClientState (GL_NORMAL_ARRAY);
117 glBindBuffer (GL_ARRAY_BUFFER, s->bufid[N_IDX]);
118 glNormalPointer (GL_FLOAT, 0, NULL);
120 glEnableClientState (GL_TEXTURE_COORD_ARRAY);
121 glBindBuffer (GL_ARRAY_BUFFER, s->bufid[UV_IDX]);
122 glTexCoordPointer (2, GL_FLOAT, 0, NULL);
124 glEnableClientState (GL_COLOR_ARRAY);
125 glBindBuffer (GL_ARRAY_BUFFER, s->bufid[C_IDX]);
126 glColorPointer (4, GL_UNSIGNED_BYTE, 0, NULL);
128 return Val_unit;
131 CAMLprim value ml_skin_draw_end (value unit_v)
133 (void) unit_v;
134 glDisableClientState (GL_VERTEX_ARRAY);
135 glDisableClientState (GL_NORMAL_ARRAY);
136 glDisableClientState (GL_TEXTURE_COORD_ARRAY);
137 glDisableClientState (GL_COLOR_ARRAY);
138 glBindBuffer (GL_ARRAY_BUFFER, 0);
139 return Val_unit;
142 CAMLprim value ml_skin_init (value geom_v)
144 CAMLparam1 (geom_v);
145 CAMLlocal5 (vertexa_v, normala_v, uva_v, skin_v, colors_v);
146 State *s = &glob_state;
148 #ifdef _WIN32
149 GETPA (BindBuffer);
150 GETPA (GenBuffers);
151 GETPA (BufferData);
152 GETPA (MapBuffer);
153 GETPA (UnmapBuffer);
154 #endif
155 vertexa_v = Field (geom_v, 0);
156 normala_v = Field (geom_v, 1);
157 uva_v = Field (geom_v, 2);
158 skin_v = Field (geom_v, 3);
159 colors_v = Field (geom_v, 4);
161 skin_init (s, vertexa_v, normala_v, uva_v, skin_v, colors_v);
162 CAMLreturn (Val_unit);
165 static void translate (State *s, float *vdst, float *ndst)
167 int i, j;
168 struct bone *b;
169 float *vsrc = s->ptrs[V_IDX];
170 float *nsrc = s->ptrs[N_IDX];
171 struct skin *skin = s->skin;
173 for (i = 0; i < s->num_vertices; ++i,
174 vsrc += 3, nsrc += 3, vdst += 3, ndst += 3, ++skin)
176 int z = 0;
177 #ifdef USE_ALTIVEC
178 float v[4] A16 = {0,0,0,0}, n[4] A16= {0,0,0,0};
179 float v0[4] A16, v1[4] A16, m[16] A16, n1[4];
180 float w;
182 vcopy (n1, nsrc);
183 #else
184 float v[3] = {0,0,0}, n[3] = {0,0,0}, v0[3], v1[3], w, m[12];
185 float *n1 = nsrc;
186 #endif
188 for (j = 0; j < skin->num_bones; ++j) {
189 w = skin->weights[j];
190 b = &s->bones[skin->boneindices[j]];
192 if (w < 0.0) z = 1;
193 vsub (v0, vsrc, b->mv);
194 mapply_to_vector (v1, b->im, v0);
196 mscale (m, b->am, w);
197 mapply_to_point (v0, m, v1);
198 vaddto (v, v0);
200 mapply_to_vector (v0, b->im, n1);
201 mapply_to_vector (v1, m, v0);
202 vaddto (n, v1);
205 /* hack hack */
206 if (z) vcopy (v, vsrc);
207 vcopy (vdst, v);
208 vcopy (ndst, n);
213 CAMLprim value ml_skin_set_skel (value skel_v)
215 int i;
216 size_t size;
217 struct bone *b;
218 CAMLparam1 (skel_v);
219 CAMLlocal2 (v, floats_v);
220 State *s = &glob_state;
222 s->num_bones = Wosize_val (skel_v);
223 size = (s->num_bones + 1) * sizeof (struct bone);
224 s->bones = b = simd_alloc (16, size);
226 memset (b, 0, size);
227 b->parent = -1;
228 b->q[3] = 1.0;
229 b->mq[3] = 1.0;
230 b->aq[3] = 1.0;
231 b->amq[3] = 1.0;
232 b++;
234 for (i = 0; i < s->num_bones; ++i, ++b) {
235 v = Field (skel_v, i);
236 floats_v = Field (v, 1);
238 b->parent = Int_val (Field (v, 0)) + 1;
240 b->v[0] = Double_field (floats_v, 1);
241 b->v[1] = Double_field (floats_v, 2);
242 b->v[2] = Double_field (floats_v, 3);
244 b->q[0] = Double_field (floats_v, 5);
245 b->q[1] = Double_field (floats_v, 6);
246 b->q[2] = Double_field (floats_v, 7);
247 b->q[3] = Double_field (floats_v, 8);
250 b = s->bones + 1;
251 for (i = 0; i < s->num_bones; ++i, ++b) {
252 float v[3], q[4], z[3] = {0,0,0};
253 struct bone *parent = &s->bones[b->parent];
255 qapply (v, parent->mq, b->v);
256 qcompose (b->mq, b->q, parent->mq);
257 vadd (b->mv, v, parent->mv);
259 qconjugate (q, b->mq);
260 q2matrix (b->im, q, z);
263 CAMLreturn (Val_unit);
266 CAMLprim value ml_skin_set_anim (value anim_v)
268 int i;
269 CAMLparam1 (anim_v);
270 CAMLlocal1 (floats_v);
271 State *s = &glob_state;
272 struct bone *b = s->bones + 1;
274 for (i = 0; i < s->num_bones; ++i, ++b) {
275 floats_v = Field (anim_v, i);
276 b->aq[0] = Double_field (floats_v, 0);
277 b->aq[1] = Double_field (floats_v, 1);
278 b->aq[2] = Double_field (floats_v, 2);
279 b->aq[3] = Double_field (floats_v, 3);
282 b = s->bones + 1;
283 for (i = 0; i < s->num_bones; ++i, ++b) {
284 float v[3];
285 struct bone *parent = &s->bones[b->parent];
287 qapply (v, parent->amq, b->v);
288 qcompose (b->amq, b->aq, parent->amq);
289 vadd (b->amv, v, parent->amv);
291 q2matrix (b->am, b->amq, b->amv);
294 CAMLreturn (Val_unit);
297 CAMLprim value ml_skin_anim (value unit_v)
299 GLboolean ret;
300 CAMLparam1 (unit_v);
301 float *vdst, *vsrc, *ndst, *nsrc;
302 State *s = &glob_state;
304 glBindBuffer (GL_ARRAY_BUFFER, s->bufid[V_IDX]);
305 vdst = glMapBuffer (GL_ARRAY_BUFFER, GL_WRITE_ONLY);
306 if (!vdst) {
307 fprintf (stderr, "glMapBuffer for vertices failed\n");
308 exit (EXIT_FAILURE);
311 glBindBuffer (GL_ARRAY_BUFFER, s->bufid[N_IDX]);
312 ndst = glMapBuffer (GL_ARRAY_BUFFER, GL_WRITE_ONLY);
313 if (!ndst) {
314 fprintf (stderr, "glMapBuffer for normals failed\n");
315 exit (EXIT_FAILURE);
318 vsrc = s->ptrs[V_IDX];
319 nsrc = s->ptrs[N_IDX];
321 translate (s, vdst, ndst);
323 glBindBuffer (GL_ARRAY_BUFFER, s->bufid[V_IDX]);
324 ret = glUnmapBuffer (GL_ARRAY_BUFFER);
325 if (ret == GL_FALSE) {
326 fprintf (stderr, "glUnmapBuffer for vertices failed\n");
327 exit (EXIT_FAILURE);
330 glBindBuffer (GL_ARRAY_BUFFER, s->bufid[N_IDX]);
331 ret = glUnmapBuffer (GL_ARRAY_BUFFER);
332 if (ret == GL_FALSE) {
333 fprintf (stderr, "glUnmapBuffer for normals failed\n");
334 exit (EXIT_FAILURE);
337 CAMLreturn (Val_unit);