Add ability to disable VBO usage, also check the required extension
[dormin.git] / skin.c
blob6cb76984634280e6bbf5b0bfe26e07e5e810c489
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 void *bufs[COUNT];
44 struct skin *skin;
45 struct bone *bones;
46 } State;
48 static State glob_state;
49 static int use_vbo;
51 static void skin_init (State *s, value vertexa_v, value normala_v,
52 value uva_v, value skin_v, value colors_v)
54 int i;
55 GLsizei size;
56 float *p;
57 struct skin *skin;
58 s->num_vertices = Wosize_val (vertexa_v) / (Double_wosize * 3);
60 if (use_vbo)
61 glGenBuffers (COUNT, s->bufid);
63 size = s->num_vertices * sizeof (GLfloat) * 3;
64 p = s->ptrs[V_IDX] = stat_alloc (size);
65 for (i = 0; i < s->num_vertices * 3; ++i) {
66 p[i] = Double_field (vertexa_v, i);
68 if (use_vbo) {
69 glBindBuffer (GL_ARRAY_BUFFER, s->bufid[V_IDX]);
70 glBufferData (GL_ARRAY_BUFFER, size, p, GL_DYNAMIC_DRAW);
72 else {
73 s->bufs[V_IDX] = simd_alloc (16, size);
74 memcpy (s->bufs[V_IDX], p, size);
77 p = s->ptrs[N_IDX] = stat_alloc (size);
78 for (i = 0; i < s->num_vertices * 3; ++i) {
79 p[i] = Double_field (normala_v, i);
81 if (use_vbo) {
82 glBindBuffer (GL_ARRAY_BUFFER, s->bufid[N_IDX]);
83 glBufferData (GL_ARRAY_BUFFER, size, p, GL_DYNAMIC_DRAW);
85 else {
86 s->bufs[N_IDX] = simd_alloc (16, size);
87 memcpy (s->bufs[N_IDX], p, size);
90 size = s->num_vertices * sizeof (GLfloat) * 2;
91 p = s->ptrs[UV_IDX] = stat_alloc (size);
92 for (i = 0; i < s->num_vertices * 2; ++i) {
93 p[i] = Double_field (uva_v, i);
95 if (use_vbo) {
96 glBindBuffer (GL_ARRAY_BUFFER, s->bufid[UV_IDX]);
97 glBufferData (GL_ARRAY_BUFFER, size, p, GL_STATIC_DRAW);
99 else {
100 s->bufs[UV_IDX] = simd_alloc (16, size);
101 memcpy (s->bufs[UV_IDX], p, size);
103 stat_free (p);
105 size = s->num_vertices * 4;
106 if (use_vbo) {
107 glBindBuffer (GL_ARRAY_BUFFER, s->bufid[C_IDX]);
108 glBufferData (GL_ARRAY_BUFFER, size, String_val (colors_v), GL_STATIC_DRAW);
110 else {
111 s->bufs[C_IDX] = simd_alloc (16, size);
112 memcpy (s->bufs[C_IDX], String_val (colors_v), size);
115 s->skin = skin = stat_alloc (s->num_vertices * sizeof (struct skin));
116 for (i = 0; i < s->num_vertices; ++i) {
117 int j;
118 value v;
120 v = Field (skin_v, i);
121 skin[i].num_bones = Int_val (Field (v, 3));
123 for (j = 0; j < skin[i].num_bones; ++j) {
124 double val;
126 val = Double_val (Bp_val (Field (v, j)));
127 skin[i].boneindices[j] = (int) val;
128 skin[i].weights[j] = val - skin[i].boneindices[j];
129 skin[i].boneindices[j] += 1;
134 CAMLprim value ml_skin_draw_begin (value unit_v)
136 State *s = &glob_state;
138 (void) unit_v;
139 glEnableClientState (GL_VERTEX_ARRAY);
140 if (use_vbo) glBindBuffer (GL_ARRAY_BUFFER, s->bufid[V_IDX]);
141 glVertexPointer (3, GL_FLOAT, 0, s->bufs[V_IDX]);
143 glEnableClientState (GL_NORMAL_ARRAY);
144 if (use_vbo) glBindBuffer (GL_ARRAY_BUFFER, s->bufid[N_IDX]);
145 glNormalPointer (GL_FLOAT, 0, s->bufs[V_IDX]);
147 glEnableClientState (GL_TEXTURE_COORD_ARRAY);
148 if (use_vbo) glBindBuffer (GL_ARRAY_BUFFER, s->bufid[UV_IDX]);
149 glTexCoordPointer (2, GL_FLOAT, 0, s->bufs[UV_IDX]);
151 glEnableClientState (GL_COLOR_ARRAY);
152 if (use_vbo) glBindBuffer (GL_ARRAY_BUFFER, s->bufid[C_IDX]);
153 glColorPointer (4, GL_UNSIGNED_BYTE, 0, s->bufs[C_IDX]);
155 return Val_unit;
158 CAMLprim value ml_skin_draw_end (value unit_v)
160 (void) unit_v;
161 glDisableClientState (GL_VERTEX_ARRAY);
162 glDisableClientState (GL_NORMAL_ARRAY);
163 glDisableClientState (GL_TEXTURE_COORD_ARRAY);
164 glDisableClientState (GL_COLOR_ARRAY);
165 if (use_vbo) glBindBuffer (GL_ARRAY_BUFFER, 0);
166 return Val_unit;
169 CAMLprim value ml_skin_init (value use_vbo_v, value geom_v)
171 CAMLparam2 (use_vbo_v, geom_v);
172 CAMLlocal5 (vertexa_v, normala_v, uva_v, skin_v, colors_v);
173 State *s = &glob_state;
175 use_vbo = Bool_val (use_vbo_v);
176 #ifdef _WIN32
177 if (use_vbo) {
178 GETPA (BindBuffer);
179 GETPA (GenBuffers);
180 GETPA (BufferData);
181 GETPA (MapBuffer);
182 GETPA (UnmapBuffer);
184 #endif
185 vertexa_v = Field (geom_v, 0);
186 normala_v = Field (geom_v, 1);
187 uva_v = Field (geom_v, 2);
188 skin_v = Field (geom_v, 3);
189 colors_v = Field (geom_v, 4);
191 skin_init (s, vertexa_v, normala_v, uva_v, skin_v, colors_v);
192 CAMLreturn (Val_unit);
195 static void translate (State *s, float *vdst, float *ndst)
197 int i, j;
198 struct bone *b;
199 float *vsrc = s->ptrs[V_IDX];
200 float *nsrc = s->ptrs[N_IDX];
201 struct skin *skin = s->skin;
203 for (i = 0; i < s->num_vertices; ++i,
204 vsrc += 3, nsrc += 3, vdst += 3, ndst += 3, ++skin)
206 int z = 0;
207 #ifdef USE_ALTIVEC
208 float v[4] A16 = {0,0,0,0}, n[4] A16 = {0,0,0,0};
209 float v0[4] A16, v1[4] A16, m[16] A16, n1[4] A16;
210 float w;
212 vcopy (n1, nsrc);
213 #else
214 float v[3] = {0,0,0}, n[3] = {0,0,0}, v0[3], v1[3], w, m[12];
215 float *n1 = nsrc;
216 #endif
217 for (j = 0; j < skin->num_bones; ++j) {
218 w = skin->weights[j];
219 b = &s->bones[skin->boneindices[j]];
221 if (w < 0.0) z = 1;
222 vsub (v0, vsrc, b->mv);
223 mapply_to_vector (v1, b->im, v0);
225 mscale (m, b->am, w);
226 mapply_to_point (v0, m, v1);
227 vaddto (v, v0);
229 mapply_to_vector (v0, b->im, n1);
230 mapply_to_vector (v1, m, v0);
231 vaddto (n, v1);
234 /* hack hack */
235 if (z) vcopy (vdst, vsrc);
236 else vcopy (vdst, v);
237 vcopy (ndst, n);
241 CAMLprim value ml_skin_set_skel (value skel_v)
243 int i;
244 size_t size;
245 struct bone *b;
246 CAMLparam1 (skel_v);
247 CAMLlocal2 (v, floats_v);
248 State *s = &glob_state;
250 s->num_bones = Wosize_val (skel_v);
251 size = (s->num_bones + 1) * sizeof (struct bone);
252 s->bones = b = simd_alloc (16, size);
254 memset (b, 0, size);
255 b->parent = -1;
256 b->q[3] = 1.0;
257 b->mq[3] = 1.0;
258 b->aq[3] = 1.0;
259 b->amq[3] = 1.0;
260 b++;
262 for (i = 0; i < s->num_bones; ++i, ++b) {
263 v = Field (skel_v, i);
264 floats_v = Field (v, 1);
266 b->parent = Int_val (Field (v, 0)) + 1;
268 b->v[0] = Double_field (floats_v, 1);
269 b->v[1] = Double_field (floats_v, 2);
270 b->v[2] = Double_field (floats_v, 3);
272 b->q[0] = Double_field (floats_v, 5);
273 b->q[1] = Double_field (floats_v, 6);
274 b->q[2] = Double_field (floats_v, 7);
275 b->q[3] = Double_field (floats_v, 8);
278 b = s->bones + 1;
279 for (i = 0; i < s->num_bones; ++i, ++b) {
280 float v[3], q[4], z[3] = {0,0,0};
281 struct bone *parent = &s->bones[b->parent];
283 qapply (v, parent->mq, b->v);
284 qcompose (b->mq, b->q, parent->mq);
285 vadd (b->mv, v, parent->mv);
287 qconjugate (q, b->mq);
288 q2matrix (b->im, q, z);
291 CAMLreturn (Val_unit);
294 CAMLprim value ml_skin_set_anim (value anim_v)
296 int i;
297 CAMLparam1 (anim_v);
298 CAMLlocal1 (floats_v);
299 State *s = &glob_state;
300 struct bone *b = s->bones + 1;
302 for (i = 0; i < s->num_bones; ++i, ++b) {
303 floats_v = Field (anim_v, i);
304 b->aq[0] = Double_field (floats_v, 0);
305 b->aq[1] = Double_field (floats_v, 1);
306 b->aq[2] = Double_field (floats_v, 2);
307 b->aq[3] = Double_field (floats_v, 3);
310 b = s->bones + 1;
311 for (i = 0; i < s->num_bones; ++i, ++b) {
312 float v[3];
313 struct bone *parent = &s->bones[b->parent];
315 qapply (v, parent->amq, b->v);
316 qcompose (b->amq, b->aq, parent->amq);
317 vadd (b->amv, v, parent->amv);
319 q2matrix (b->am, b->amq, b->amv);
322 CAMLreturn (Val_unit);
325 CAMLprim value ml_skin_anim (value unit_v)
327 GLboolean ret;
328 CAMLparam1 (unit_v);
329 float *vdst, *vsrc, *ndst, *nsrc;
330 State *s = &glob_state;
332 if (use_vbo) {
333 glBindBuffer (GL_ARRAY_BUFFER, s->bufid[V_IDX]);
334 vdst = glMapBuffer (GL_ARRAY_BUFFER, GL_WRITE_ONLY);
335 if (!vdst) {
336 fprintf (stderr, "glMapBuffer for vertices failed\n");
337 exit (EXIT_FAILURE);
340 glBindBuffer (GL_ARRAY_BUFFER, s->bufid[N_IDX]);
341 ndst = glMapBuffer (GL_ARRAY_BUFFER, GL_WRITE_ONLY);
342 if (!ndst) {
343 fprintf (stderr, "glMapBuffer for normals failed\n");
344 exit (EXIT_FAILURE);
347 else {
348 vdst = s->bufs[V_IDX];
349 ndst = s->bufs[N_IDX];
352 vsrc = s->ptrs[V_IDX];
353 nsrc = s->ptrs[N_IDX];
355 translate (s, vdst, ndst);
357 if (use_vbo) {
358 glBindBuffer (GL_ARRAY_BUFFER, s->bufid[V_IDX]);
359 ret = glUnmapBuffer (GL_ARRAY_BUFFER);
360 if (ret == GL_FALSE) {
361 fprintf (stderr, "glUnmapBuffer for vertices failed\n");
362 exit (EXIT_FAILURE);
365 glBindBuffer (GL_ARRAY_BUFFER, s->bufid[N_IDX]);
366 ret = glUnmapBuffer (GL_ARRAY_BUFFER);
367 if (ret == GL_FALSE) {
368 fprintf (stderr, "glUnmapBuffer for normals failed\n");
369 exit (EXIT_FAILURE);
373 CAMLreturn (Val_unit);