Remove negative weight hack
[dormin.git] / skinvp.c
blob8b5cf3b14dd4e5660c9015ffe8ffc89a76cf6b8d
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 #define USE_VP
12 #include "vec.c"
13 #include "pgl.h"
15 #ifdef _MSC_VER
16 #define snprintf _snprintf
17 #endif
19 enum {V_IDX, N_IDX, UV_IDX, C_IDX, A_IDX, COUNT};
21 struct skin {
22 int boneindices[3];
23 float weights[3];
24 int num_bones;
27 struct bone {
28 int parent;
30 float v[4];
31 float q[4];
33 float mv[4];
34 float mq[4];
36 float aq[4];
37 float amq[4];
38 float amv[4];
40 float cm[12];
43 struct adescr {
44 int size;
45 int norm;
46 int index;
47 int stride;
48 int offset;
49 int num_elems;
50 GLenum type;
53 const struct adescr ad[] = {
54 { 4, 0, 0, 12, 0, 3, GL_FLOAT },
55 { 4, 0, 2, 12, 0, 3, GL_FLOAT },
56 { 4, 0, 8, 8, 0, 2, GL_FLOAT },
57 { 1, 1, 3, 4, 0, 4, GL_UNSIGNED_BYTE },
58 { 4, 0, 6, 12, 0, 3, GL_FLOAT }
61 typedef struct {
62 char *array;
63 int num_bones;
64 int num_vertices;
65 GLuint bufid;
66 struct adescr ad[COUNT];
67 struct skin *skin;
68 struct bone *bones;
69 } State;
71 static State glob_state;
72 static int use_vbo;
74 static void skin_init (State *s, value vertexa_v, value normala_v,
75 value uva_v, value skin_v, value colors_v,
76 int interleave)
78 int i;
79 char *p;
80 char *map;
81 GLsizei size;
82 struct skin *skin;
83 GLsizei offset = 0;
84 GLsizei stride = 12 * sizeof (GLfloat);
85 GLsizei strides[COUNT];
87 s->num_vertices = Wosize_val (vertexa_v) / (Double_wosize * 3);
89 for (i = 0, size = 0; i < COUNT; ++i) {
90 s->ad[i].index = ad[i].index;
91 if (interleave) {
92 s->ad[i].offset = offset;
93 s->ad[i].stride = stride;
94 strides[i] = stride;
95 offset += ad[i].stride;
97 else {
98 strides[i] = ad[i].stride;
99 s->ad[i].offset = size;
100 s->ad[i].stride =
101 ad[i].num_elems*ad[i].size == ad[i].stride
103 : ad[i].stride
106 s->ad[i].norm = ad[i].norm;
107 s->ad[i].type = ad[i].type;
108 s->ad[i].num_elems = ad[i].num_elems;
109 s->ad[i].size = ad[i].num_elems * ad[i].size * s->num_vertices;
110 size += s->ad[i].size;
113 if (use_vbo) {
114 glGenBuffers (1, &s->bufid);
115 glBindBuffer (GL_ARRAY_BUFFER, s->bufid);
116 glBufferData (GL_ARRAY_BUFFER, size, NULL, GL_STATIC_DRAW);
117 map = glMapBuffer (GL_ARRAY_BUFFER, GL_WRITE_ONLY);
118 if (!map) caml_failwith ("glMapBuffer failed");
120 else {
121 map = stat_alloc (size);
124 p = map + s->ad[V_IDX].offset;
125 for (i = 0; i < s->num_vertices; ++i) {
126 ((float *) p)[0] = Double_field (vertexa_v, i*3 + 0);
127 ((float *) p)[1] = Double_field (vertexa_v, i*3 + 1);
128 ((float *) p)[2] = Double_field (vertexa_v, i*3 + 2);
129 p += strides[V_IDX];
132 p = map + s->ad[N_IDX].offset;
133 for (i = 0; i < s->num_vertices; ++i) {
134 ((float *) p)[0] = Double_field (normala_v, i*3 + 0);
135 ((float *) p)[1] = Double_field (normala_v, i*3 + 1);
136 ((float *) p)[2] = Double_field (normala_v, i*3 + 2);
137 p += strides[N_IDX];
140 p = map + s->ad[UV_IDX].offset;
141 for (i = 0; i < s->num_vertices; ++i) {
142 ((float *) p)[0] = Double_field (uva_v, i*2 + 0);
143 ((float *) p)[1] = Double_field (uva_v, i*2 + 1);
144 p += strides[UV_IDX];
147 p = map + s->ad[C_IDX].offset;
149 for (i = 0; i < s->num_vertices; ++i) {
150 memcpy (p, String_val (colors_v) + i*4, 4);
151 p += strides[C_IDX];
154 s->skin = skin = stat_alloc (s->num_vertices * sizeof (struct skin));
155 p = map + s->ad[A_IDX].offset;
157 for (i = 0; i < s->num_vertices; ++i) {
158 int j;
159 value v;
161 v = Field (skin_v, i);
162 skin[i].num_bones = Int_val (Field (v, 3));
164 for (j = 0; j < skin[i].num_bones; ++j) {
165 double val, w;
167 val = Double_val (Bp_val (Field (v, j)));
168 skin[i].boneindices[j] = (int) val;
169 w = val - skin[i].boneindices[j];
170 skin[i].weights[j] = w;
171 skin[i].boneindices[j] += 1;
172 ((float *) p)[j] = skin[i].boneindices[j] * 3 + w;
175 for (j = skin[i].num_bones; j < 3; ++j) {
176 ((float *) p)[j] = 0.0;
178 p += strides[A_IDX];
181 if (use_vbo) {
182 if (glUnmapBuffer (GL_ARRAY_BUFFER) == GL_FALSE)
183 caml_failwith ("glUnmapBuffer failed");
185 else {
186 s->array = map;
190 static void skin_anim (State *s)
192 int i, j = 3;
193 struct bone *b = s->bones + 1;
195 for (i = 0; i < s->num_bones; ++i, ++b, j += 3) {
196 glProgramLocalParameter4fvARB (GL_VERTEX_PROGRAM_ARB, j + 0, b->cm + 0);
197 glProgramLocalParameter4fvARB (GL_VERTEX_PROGRAM_ARB, j + 1, b->cm + 4);
198 glProgramLocalParameter4fvARB (GL_VERTEX_PROGRAM_ARB, j + 2, b->cm + 8);
202 static void load_program (const char *text, GLsizei size, GLuint progid)
204 glBindProgramARB (GL_VERTEX_PROGRAM_ARB, progid);
206 glProgramStringARB (GL_VERTEX_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB,
207 size, (const GLubyte *) text);
208 if (glGetError () != GL_NO_ERROR) {
209 GLint pos;
210 char buf[1024];
212 glGetIntegerv (GL_PROGRAM_ERROR_POSITION_ARB, &pos);
213 snprintf (buf, 1024, "glProgramStringARB: error %s at %d",
214 (char *) glGetString (GL_PROGRAM_ERROR_STRING_ARB), pos);
215 caml_failwith (buf);
218 float r[4];
220 memset (r, 0, sizeof (r));
221 glProgramLocalParameter4fvARB (GL_VERTEX_PROGRAM_ARB, 0, r);
222 glProgramLocalParameter4fvARB (GL_VERTEX_PROGRAM_ARB, 0, r);
223 glProgramLocalParameter4fvARB (GL_VERTEX_PROGRAM_ARB, 0, r);
224 glProgramLocalParameter4fvARB (GL_VERTEX_PROGRAM_ARB, 0, r);
228 CAMLprim value ml_skin_draw_begin_vp (value unit_v)
230 int i;
231 State *s = &glob_state;
233 (void) unit_v;
235 glBindBuffer (GL_ARRAY_BUFFER, s->bufid);
237 for (i = 0; i < COUNT; ++i) {
238 struct adescr *ad = &s->ad[i];
240 glEnableVertexAttribArrayARB (ad->index);
241 glVertexAttribPointerARB (ad->index, ad->num_elems, ad->type,
242 ad->norm, ad->stride, s->array + ad->offset);
245 glEnable (GL_VERTEX_PROGRAM_ARB);
246 return Val_unit;
249 CAMLprim value ml_skin_draw_end_vp (value unit_v)
251 int i;
252 State *s = &glob_state;
254 (void) unit_v;
256 for (i = 0; i < COUNT; ++i)
257 glDisableVertexAttribArrayARB (s->ad[i].index);
259 glBindBuffer (GL_ARRAY_BUFFER, 0);
260 glDisable (GL_VERTEX_PROGRAM_ARB);
261 return Val_unit;
264 CAMLprim value ml_skin_init_vp (value use_vbo_v, value geom_v)
266 CAMLparam2 (use_vbo_v, geom_v);
267 CAMLlocal5 (vertexa_v, normala_v, uva_v, skin_v, colors_v);
268 State *s = &glob_state;
270 use_vbo = Bool_val (use_vbo_v);
271 #ifdef _WIN32
272 GETPA (BindBuffer);
273 GETPA (GenBuffers);
274 GETPA (BufferData);
275 GETPA (MapBuffer);
276 GETPA (UnmapBuffer);
277 GETPA (BindProgramARB);
278 GETPA (ProgramStringARB);
279 GETPA (ProgramLocalParameter4fvARB);
280 GETPA (EnableVertexAttribArrayARB);
281 GETPA (DisableVertexAttribArrayARB);
282 GETPA (VertexAttribPointerARB);
283 #endif
285 vertexa_v = Field (geom_v, 0);
286 normala_v = Field (geom_v, 1);
287 uva_v = Field (geom_v, 2);
288 skin_v = Field (geom_v, 3);
289 colors_v = Field (geom_v, 4);
291 skin_init (s, vertexa_v, normala_v, uva_v, skin_v, colors_v, 1);
293 CAMLreturn (Val_unit);
296 CAMLprim value ml_skin_set_skel_vp (value skel_v)
298 int i;
299 size_t size;
300 struct bone *b;
301 CAMLparam1 (skel_v);
302 CAMLlocal2 (v, floats_v);
303 State *s = &glob_state;
305 s->num_bones = Wosize_val (skel_v);
306 size = (s->num_bones + 1) * sizeof (struct bone);
307 s->bones = b = stat_alloc (size);
309 memset (b, 0, size);
310 b->parent = -1;
311 b->q[3] = 1.0;
312 b->mq[3] = 1.0;
313 b->aq[3] = 1.0;
314 b->amq[3] = 1.0;
315 b++;
317 for (i = 0; i < s->num_bones; ++i, ++b) {
318 v = Field (skel_v, i);
319 floats_v = Field (v, 1);
321 b->parent = Int_val (Field (v, 0)) + 1;
323 b->v[0] = Double_field (floats_v, 1);
324 b->v[1] = Double_field (floats_v, 2);
325 b->v[2] = Double_field (floats_v, 3);
327 b->q[0] = Double_field (floats_v, 5);
328 b->q[1] = Double_field (floats_v, 6);
329 b->q[2] = Double_field (floats_v, 7);
330 b->q[3] = Double_field (floats_v, 8);
333 b = s->bones + 1;
334 for (i = 0; i < s->num_bones; ++i, ++b) {
335 float v[3];
336 struct bone *parent = &s->bones[b->parent];
338 qapply (v, parent->mq, b->v);
339 qcompose (b->mq, b->q, parent->mq);
340 vadd (b->mv, v, parent->mv);
342 memset (b->cm, 0, sizeof (b->cm));
343 b->cm[0] = 1.0;
344 b->cm[5] = 1.0;
345 b->cm[10] = 1.0;
348 CAMLreturn (Val_unit);
351 CAMLprim value ml_skin_set_anim_vp (value anim_v)
353 int i;
354 CAMLparam1 (anim_v);
355 CAMLlocal1 (floats_v);
356 State *s = &glob_state;
357 struct bone *b = s->bones + 1;
359 for (i = 0; i < s->num_bones; ++i, ++b) {
360 floats_v = Field (anim_v, i);
361 b->aq[0] = Double_field (floats_v, 0);
362 b->aq[1] = Double_field (floats_v, 1);
363 b->aq[2] = Double_field (floats_v, 2);
364 b->aq[3] = Double_field (floats_v, 3);
367 b = s->bones + 1;
368 for (i = 0; i < s->num_bones; ++i, ++b) {
369 float v[4], v1[4], q[4], q1[4];
370 struct bone *parent = &s->bones[b->parent];
372 qapply (v, parent->amq, b->v);
373 qcompose (b->amq, b->aq, parent->amq);
374 vadd (b->amv, v, parent->amv);
376 qconjugate (q1, b->mq);
377 qcompose (q, q1, b->amq);
379 qapply (v, q, b->mv);
380 vsub (v1, b->amv, v);
381 q2matrixt (b->cm, q, v1);
384 CAMLreturn (Val_unit);
387 CAMLprim value ml_skin_anim_vp (value unit_v)
389 CAMLparam1 (unit_v);
390 State *s = &glob_state;
392 skin_anim (s);
393 CAMLreturn (Val_unit);
396 CAMLprim value ml_skin_set_text_vp (value text_v)
398 CAMLparam1 (text_v);
399 State *s = &glob_state;
401 load_program (String_val (text_v), caml_string_length (text_v), 1);
402 skin_anim (s);
403 CAMLreturn (Val_unit);