Support zooming with mouse
[dormin.git] / skin.c
blobbf9a0f233a6b501acdeb3f36918a40117a6f237a
1 #define GL_GLEXT_PROTOTYPES
2 #ifdef _WIN32
3 #define WIN32_LEAN_AND_MEAN
4 #include <windows.h>
5 #endif
6 #ifdef __APPLE__
7 #include <OpenGL/gl.h>
8 #else
9 #include <GL/gl.h>
10 #endif
12 #ifndef GL_VERSION_1_5
13 #define GL_ARRAY_BUFFER 0x8892
14 #define GL_DYNAMIC_DRAW 0x88E8
15 #define GL_STATIC_DRAW 0x88E4
16 #define GL_WRITE_ONLY 0x88B9
17 #ifndef APIENTRYP
18 #define APIENTRYP APIENTRY *
19 #endif
20 typedef ptrdiff_t GLintptr;
21 typedef ptrdiff_t GLsizeiptr;
22 typedef void (APIENTRYP PFNGLBINDBUFFERPROC) (GLenum target, GLuint buffer);
23 typedef void (APIENTRYP PFNGLGENBUFFERSPROC) (GLsizei n, GLuint *buffers);
24 typedef void (APIENTRYP PFNGLBUFFERDATAPROC) (GLenum target, GLsizeiptr size, const GLvoid *data, GLenum usage);
25 typedef GLvoid* (APIENTRYP PFNGLMAPBUFFERPROC) (GLenum target, GLenum access);
26 typedef GLboolean (APIENTRYP PFNGLUNMAPBUFFERPROC) (GLenum target);
27 static PFNGLBINDBUFFERPROC glBindBuffer;
28 static PFNGLGENBUFFERSPROC glGenBuffers;
29 static PFNGLBUFFERDATAPROC glBufferData;
30 static PFNGLMAPBUFFERPROC glMapBuffer;
31 static PFNGLUNMAPBUFFERPROC glUnmapBuffer;
32 #define GETPA(name) for (;;) { \
33 *(PROC *) &gl##name = wglGetProcAddress ("gl" # name); \
34 if (!gl##name) { \
35 fprintf (stderr, "could not get address of gl"#name"\n"); \
36 exit (EXIT_FAILURE); \
37 } \
38 break; \
40 #endif
42 #include <math.h>
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <string.h>
47 #include <caml/fail.h>
48 #include <caml/alloc.h>
49 #include <caml/memory.h>
51 #include "vec.c"
53 enum {V_IDX, N_IDX, UV_IDX, C_IDX, COUNT};
55 struct skin {
56 int boneindices[3];
57 float weights[3];
58 int num_bones;
61 struct bone {
62 int parent;
63 float v[3];
64 float q[4];
66 float mv[3];
67 float mq[4];
69 float aq[4];
70 float amq[4];
71 float amv[3];
73 float am[12];
74 float im[12];
77 typedef struct {
78 int num_bones;
79 int num_vertices;
80 GLuint bufid[COUNT];
81 float *ptrs[COUNT];
82 struct skin *skin;
83 struct bone *bones;
84 } State;
86 static State glob_state;
88 static void skin_init (State *s, value vertexa_v, value normala_v,
89 value uva_v, value skin_v, value colors_v)
91 int i;
92 GLsizei size;
93 float *p;
94 struct skin *skin;
95 s->num_vertices = Wosize_val (vertexa_v) / (Double_wosize * 3);
97 glGenBuffers (COUNT, s->bufid);
99 size = s->num_vertices * sizeof (GLfloat) * 3;
100 p = s->ptrs[V_IDX] = stat_alloc (size);
101 for (i = 0; i < s->num_vertices * 3; ++i) {
102 p[i] = Double_field (vertexa_v, i);
104 glBindBuffer (GL_ARRAY_BUFFER, s->bufid[V_IDX]);
105 glBufferData (GL_ARRAY_BUFFER, size, p, GL_DYNAMIC_DRAW);
107 p = s->ptrs[N_IDX] = stat_alloc (size);
108 for (i = 0; i < s->num_vertices * 3; ++i) {
109 p[i] = Double_field (normala_v, i);
111 glBindBuffer (GL_ARRAY_BUFFER, s->bufid[N_IDX]);
112 glBufferData (GL_ARRAY_BUFFER, size, p, GL_DYNAMIC_DRAW);
114 size = s->num_vertices * sizeof (GLfloat) * 2;
115 p = s->ptrs[UV_IDX] = stat_alloc (size);
116 for (i = 0; i < s->num_vertices * 2; ++i) {
117 p[i] = Double_field (uva_v, i);
119 glBindBuffer (GL_ARRAY_BUFFER, s->bufid[UV_IDX]);
120 glBufferData (GL_ARRAY_BUFFER, size, p, GL_STATIC_DRAW);
121 stat_free (p);
123 size = s->num_vertices * 4;
124 glBindBuffer (GL_ARRAY_BUFFER, s->bufid[C_IDX]);
125 glBufferData (GL_ARRAY_BUFFER, size, String_val (colors_v), GL_STATIC_DRAW);
127 s->skin = skin = stat_alloc (s->num_vertices * sizeof (struct skin));
128 for (i = 0; i < s->num_vertices; ++i) {
129 int j;
130 value v;
132 v = Field (skin_v, i);
133 skin[i].num_bones = Int_val (Field (v, 3));
135 for (j = 0; j < skin[i].num_bones; ++j) {
136 double val;
138 val = Double_val (Bp_val (Field (v, j)));
139 skin[i].boneindices[j] = (int) val;
140 skin[i].weights[j] = val - skin[i].boneindices[j];
141 skin[i].boneindices[j] += 1;
146 CAMLprim value ml_skin_draw_begin (value unit_v)
148 State *s = &glob_state;
150 glEnableClientState (GL_VERTEX_ARRAY);
151 glBindBuffer (GL_ARRAY_BUFFER, s->bufid[V_IDX]);
152 glVertexPointer (3, GL_FLOAT, 0, NULL);
154 glEnableClientState (GL_NORMAL_ARRAY);
155 glBindBuffer (GL_ARRAY_BUFFER, s->bufid[N_IDX]);
156 glNormalPointer (GL_FLOAT, 0, NULL);
158 glEnableClientState (GL_TEXTURE_COORD_ARRAY);
159 glBindBuffer (GL_ARRAY_BUFFER, s->bufid[UV_IDX]);
160 glTexCoordPointer (2, GL_FLOAT, 0, NULL);
162 glEnableClientState (GL_COLOR_ARRAY);
163 glBindBuffer (GL_ARRAY_BUFFER, s->bufid[C_IDX]);
164 glColorPointer (4, GL_UNSIGNED_BYTE, 0, NULL);
166 return Val_unit;
169 CAMLprim value ml_skin_draw_end (value uint_v)
171 glDisableClientState (GL_VERTEX_ARRAY);
172 glDisableClientState (GL_NORMAL_ARRAY);
173 glDisableClientState (GL_TEXTURE_COORD_ARRAY);
174 glDisableClientState (GL_COLOR_ARRAY);
175 glBindBuffer (GL_ARRAY_BUFFER, 0);
177 #if 0
178 glDisable (GL_TEXTURE_2D);
179 glDisable (GL_LIGHTING);
180 glColor3f (1.0, 0.0, 0.0);
181 glDisable (GL_DEPTH_TEST);
182 glLineWidth (4.0);
184 glBegin (GL_LINES);
186 int i;
187 State *s = &glob_state;
188 struct bone *b = s->bones + 1;
190 for (i = 0; i < s->num_bones; ++i, ++b) {
191 struct bone *p = &s->bones[b->parent];
193 glVertex3fv (p->amv);
194 glVertex3fv (b->amv);
197 glEnd ();
198 #endif
199 return Val_unit;
202 CAMLprim value ml_skin_init (value geom_v)
204 CAMLparam1 (geom_v);
205 CAMLlocal5 (vertexa_v, normala_v, uva_v, skin_v, colors_v);
206 State *s = &glob_state;
208 #ifdef _WIN32
209 GETPA (BindBuffer);
210 GETPA (GenBuffers);
211 GETPA (BufferData);
212 GETPA (MapBuffer);
213 GETPA (UnmapBuffer);
214 #endif
215 vertexa_v = Field (geom_v, 0);
216 normala_v = Field (geom_v, 1);
217 uva_v = Field (geom_v, 2);
218 skin_v = Field (geom_v, 3);
219 colors_v = Field (geom_v, 4);
221 skin_init (s, vertexa_v, normala_v, uva_v, skin_v, colors_v);
222 CAMLreturn (Val_unit);
225 static void translate (State *s, float *dst)
227 int i, j;
228 struct bone *b;
229 float *curvert = s->ptrs[V_IDX];
230 struct skin *skin = s->skin;
232 for (i = 0; i < s->num_vertices; ++i, curvert += 3, dst += 3, ++skin)
234 float v[3] = {0,0,0}, v0[3], v1[3], v2[3], w, m[12];
236 for (j = 0; j < skin->num_bones; ++j) {
237 w = skin->weights[j] + 0.000011;
238 b = &s->bones[skin->boneindices[j]];
240 vsub (v0, curvert, b->mv);
241 mapply_to_vector (v1, b->im, v0);
243 mscale (m, b->am, w);
244 mapply_to_point (v2, m, v1);
246 vaddto (v, v2);
248 vcopy (dst, v);
253 CAMLprim value ml_skin_set_skel (value skel_v)
255 int i;
256 size_t size;
257 struct bone *b;
258 CAMLparam1 (skel_v);
259 CAMLlocal2 (v, floats_v);
260 State *s = &glob_state;
262 s->num_bones = Wosize_val (skel_v);
263 size = (s->num_bones + 1) * sizeof (struct bone);
264 s->bones = b = stat_alloc (size);
266 memset (b, 0, size);
267 b->parent = -1;
268 b->q[3] = 1.0;
269 b->mq[3] = 1.0;
270 b->aq[3] = 1.0;
271 b->amq[3] = 1.0;
272 b++;
274 for (i = 0; i < s->num_bones; ++i, ++b) {
275 v = Field (skel_v, i);
276 floats_v = Field (v, 1);
278 b->parent = Int_val (Field (v, 0)) + 1;
280 b->v[0] = Double_field (floats_v, 1);
281 b->v[1] = Double_field (floats_v, 2);
282 b->v[2] = Double_field (floats_v, 3);
284 b->q[0] = Double_field (floats_v, 5);
285 b->q[1] = Double_field (floats_v, 6);
286 b->q[2] = Double_field (floats_v, 7);
287 b->q[3] = Double_field (floats_v, 8);
290 b = s->bones + 1;
291 for (i = 0; i < s->num_bones; ++i, ++b) {
292 float v[3], q[4], q1[4], z[3] = {0,0,0};
293 struct bone *parent = &s->bones[b->parent];
295 qapply (v, parent->mq, b->v);
296 qcompose (b->mq, b->q, parent->mq);
297 vadd (b->mv, v, parent->mv);
299 qconjugate (q, b->mq);
300 qscale (q1, q, 1.0 / qmagnitude (q));
301 q2matrix (b->im, q1, z);
304 CAMLreturn (Val_unit);
307 CAMLprim value ml_skin_set_anim (value anim_v)
309 int i;
310 CAMLparam1 (anim_v);
311 CAMLlocal1 (floats_v);
312 State *s = &glob_state;
313 struct bone *b = s->bones + 1;
315 for (i = 0; i < s->num_bones; ++i, ++b) {
316 floats_v = Field (anim_v, i);
317 b->aq[0] = Double_field (floats_v, 0);
318 b->aq[1] = Double_field (floats_v, 1);
319 b->aq[2] = Double_field (floats_v, 2);
320 b->aq[3] = Double_field (floats_v, 3);
323 b = s->bones + 1;
324 for (i = 0; i < s->num_bones; ++i, ++b) {
325 float v[3];
326 struct bone *parent = &s->bones[b->parent];
328 qapply (v, parent->amq, b->v);
329 qcompose (b->amq, b->aq, parent->amq);
330 vadd (b->amv, v, parent->amv);
332 q2matrix (b->am, b->amq, b->amv);
335 CAMLreturn (Val_unit);
338 CAMLprim value ml_skin_anim (value unit_v)
340 GLboolean ret;
341 CAMLparam1 (unit_v);
342 float *vdst, *vsrc, *ndst, *nsrc;
343 State *s = &glob_state;
345 glBindBuffer (GL_ARRAY_BUFFER, s->bufid[V_IDX]);
346 vdst = glMapBuffer (GL_ARRAY_BUFFER, GL_WRITE_ONLY);
347 if (!vdst) {
348 fprintf (stderr, "glMapBuffer for vertices failed\n");
349 exit (EXIT_FAILURE);
352 glBindBuffer (GL_ARRAY_BUFFER, s->bufid[N_IDX]);
353 ndst = glMapBuffer (GL_ARRAY_BUFFER, GL_WRITE_ONLY);
354 if (!ndst) {
355 fprintf (stderr, "glMapBuffer for normals failed\n");
356 exit (EXIT_FAILURE);
359 vsrc = s->ptrs[V_IDX];
360 nsrc = s->ptrs[N_IDX];
362 translate (s, vdst);
363 #if 0
365 int i;
366 for (i = 0; i < s->num_vertices; ++i) {
367 struct skin *skin;
368 struct bone *bone, *parent;
369 float v[3], v1[3], *v2;
370 float q[4];
372 skin = &s->skin[i];
373 bone = &s->bones[skin->boneindices[0]];
374 parent = &s->bones[bone->parent];
376 vdst += 3;
377 vsrc += 3;
379 *ndst++ = *nsrc++;
380 *ndst++ = *nsrc++;
381 *ndst++ = *nsrc++;
384 #endif
386 glBindBuffer (GL_ARRAY_BUFFER, s->bufid[V_IDX]);
387 ret = glUnmapBuffer (GL_ARRAY_BUFFER);
388 if (ret == GL_FALSE) {
389 fprintf (stderr, "glUnmapBuffer for vertices failed\n");
390 exit (EXIT_FAILURE);
393 glBindBuffer (GL_ARRAY_BUFFER, s->bufid[N_IDX]);
394 ret = glUnmapBuffer (GL_ARRAY_BUFFER);
395 if (ret == GL_FALSE) {
396 fprintf (stderr, "glUnmapBuffer for normals failed\n");
397 exit (EXIT_FAILURE);
400 CAMLreturn (Val_unit);