Add simple NTO viewer
[dormin.git] / skinvp.c
blob8f7d12c463c3de1d8bbf775ec4c30a4a50bdc046
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 GLint pos;
206 glBindProgramARB (GL_VERTEX_PROGRAM_ARB, progid);
208 glProgramStringARB (GL_VERTEX_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB,
209 size, (const GLubyte *) text);
210 glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &pos);
211 if (pos != -1) {
212 char buf[1024];
214 snprintf (buf, 1024, "glProgramStringARB: error %s at %d",
215 (char *) glGetString (GL_PROGRAM_ERROR_STRING_ARB), pos);
216 caml_failwith (buf);
219 float r[4];
221 memset (r, 0, sizeof (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);
225 glProgramLocalParameter4fvARB (GL_VERTEX_PROGRAM_ARB, 0, r);
229 CAMLprim value ml_skin_draw_begin_vp (value unit_v)
231 int i;
232 State *s = &glob_state;
234 (void) unit_v;
236 glBindBuffer (GL_ARRAY_BUFFER, s->bufid);
238 for (i = 0; i < COUNT; ++i) {
239 struct adescr *ad = &s->ad[i];
241 glEnableVertexAttribArrayARB (ad->index);
242 glVertexAttribPointerARB (ad->index, ad->num_elems, ad->type,
243 ad->norm, ad->stride, s->array + ad->offset);
246 glEnable (GL_VERTEX_PROGRAM_ARB);
247 return Val_unit;
250 CAMLprim value ml_skin_draw_end_vp (value unit_v)
252 int i;
253 State *s = &glob_state;
255 (void) unit_v;
257 for (i = 0; i < COUNT; ++i)
258 glDisableVertexAttribArrayARB (s->ad[i].index);
260 glBindBuffer (GL_ARRAY_BUFFER, 0);
261 glDisable (GL_VERTEX_PROGRAM_ARB);
262 return Val_unit;
265 CAMLprim value ml_skin_init_vp (value use_vbo_v, value geom_v)
267 CAMLparam2 (use_vbo_v, geom_v);
268 CAMLlocal5 (vertexa_v, normala_v, uva_v, skin_v, colors_v);
269 State *s = &glob_state;
271 use_vbo = Bool_val (use_vbo_v);
272 #ifdef _WIN32
273 GETPA (BindBuffer);
274 GETPA (GenBuffers);
275 GETPA (BufferData);
276 GETPA (MapBuffer);
277 GETPA (UnmapBuffer);
278 GETPA (BindProgramARB);
279 GETPA (ProgramStringARB);
280 GETPA (ProgramLocalParameter4fvARB);
281 GETPA (EnableVertexAttribArrayARB);
282 GETPA (DisableVertexAttribArrayARB);
283 GETPA (VertexAttribPointerARB);
284 #endif
286 vertexa_v = Field (geom_v, 0);
287 normala_v = Field (geom_v, 1);
288 uva_v = Field (geom_v, 2);
289 skin_v = Field (geom_v, 3);
290 colors_v = Field (geom_v, 4);
292 skin_init (s, vertexa_v, normala_v, uva_v, skin_v, colors_v, 1);
294 CAMLreturn (Val_unit);
297 CAMLprim value ml_skin_set_skel_vp (value skel_v)
299 int i;
300 size_t size;
301 struct bone *b;
302 CAMLparam1 (skel_v);
303 CAMLlocal2 (v, floats_v);
304 State *s = &glob_state;
306 s->num_bones = Wosize_val (skel_v);
307 size = (s->num_bones + 1) * sizeof (struct bone);
308 s->bones = b = stat_alloc (size);
310 memset (b, 0, size);
311 b->parent = -1;
312 b->q[3] = 1.0;
313 b->mq[3] = 1.0;
314 b->aq[3] = 1.0;
315 b->amq[3] = 1.0;
316 b++;
318 for (i = 0; i < s->num_bones; ++i, ++b) {
319 v = Field (skel_v, i);
320 floats_v = Field (v, 1);
322 b->parent = Int_val (Field (v, 0)) + 1;
324 b->v[0] = Double_field (floats_v, 1);
325 b->v[1] = Double_field (floats_v, 2);
326 b->v[2] = Double_field (floats_v, 3);
328 b->q[0] = Double_field (floats_v, 5);
329 b->q[1] = Double_field (floats_v, 6);
330 b->q[2] = Double_field (floats_v, 7);
331 b->q[3] = Double_field (floats_v, 8);
334 b = s->bones + 1;
335 for (i = 0; i < s->num_bones; ++i, ++b) {
336 float v[3];
337 struct bone *parent = &s->bones[b->parent];
339 qapply (v, parent->mq, b->v);
340 qcompose (b->mq, b->q, parent->mq);
341 vadd (b->mv, v, parent->mv);
343 memset (b->cm, 0, sizeof (b->cm));
344 b->cm[0] = 1.0;
345 b->cm[5] = 1.0;
346 b->cm[10] = 1.0;
349 CAMLreturn (Val_unit);
352 CAMLprim value ml_skin_set_anim_vp (value anim_v)
354 int i;
355 CAMLparam1 (anim_v);
356 CAMLlocal1 (floats_v);
357 State *s = &glob_state;
358 struct bone *b = s->bones + 1;
360 for (i = 0; i < s->num_bones; ++i, ++b) {
361 floats_v = Field (anim_v, i);
362 b->aq[0] = Double_field (floats_v, 0);
363 b->aq[1] = Double_field (floats_v, 1);
364 b->aq[2] = Double_field (floats_v, 2);
365 b->aq[3] = Double_field (floats_v, 3);
368 b = s->bones + 1;
369 for (i = 0; i < s->num_bones; ++i, ++b) {
370 float v[4], v1[4], q[4], q1[4];
371 struct bone *parent = &s->bones[b->parent];
373 qapply (v, parent->amq, b->v);
374 qcompose (b->amq, b->aq, parent->amq);
375 vadd (b->amv, v, parent->amv);
377 qconjugate (q1, b->mq);
378 qcompose (q, q1, b->amq);
380 qapply (v, q, b->mv);
381 vsub (v1, b->amv, v);
382 q2matrixt (b->cm, q, v1);
385 CAMLreturn (Val_unit);
388 CAMLprim value ml_skin_anim_vp (value unit_v)
390 CAMLparam1 (unit_v);
391 State *s = &glob_state;
393 skin_anim (s);
394 CAMLreturn (Val_unit);
397 CAMLprim value ml_skin_set_text_vp (value text_v)
399 CAMLparam1 (text_v);
400 State *s = &glob_state;
402 load_program (String_val (text_v), caml_string_length (text_v), 1);
403 skin_anim (s);
404 CAMLreturn (Val_unit);