FreeWRL/FreeX3D  3.0.0
Component_HAnim.c
1 /*
2 
3 
4 X3D H-Anim Component
5 
6 */
7 
8 
9 /****************************************************************************
10  This file is part of the FreeWRL/FreeX3D Distribution.
11 
12  Copyright 2009 CRC Canada. (http://www.crc.gc.ca)
13 
14  FreeWRL/FreeX3D is free software: you can redistribute it and/or modify
15  it under the terms of the GNU Lesser Public License as published by
16  the Free Software Foundation, either version 3 of the License, or
17  (at your option) any later version.
18 
19  FreeWRL/FreeX3D is distributed in the hope that it will be useful,
20  but WITHOUT ANY WARRANTY; without even the implied warranty of
21  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22  GNU General Public License for more details.
23 
24  You should have received a copy of the GNU General Public License
25  along with FreeWRL/FreeX3D. If not, see <http://www.gnu.org/licenses/>.
26 ****************************************************************************/
27 
28 
29 
30 #include <config.h>
31 #include <system.h>
32 #include <display.h>
33 #include <internal.h>
34 
35 #include <libFreeWRL.h>
36 
37 #include "../vrml_parser/Structs.h"
38 #include "../vrml_parser/CRoutes.h"
39 #include "../main/headers.h"
40 #include "../opengl/Material.h"
41 #include "../opengl/OpenGL_Utils.h"
42 #include "Children.h"
43 #include "../scenegraph/RenderFuncs.h"
44 #include "../opengl/Frustum.h"
45 #include "LinearAlgebra.h"
46 
47 /* #include "OpenFW_GL_Utils.h" */
48 
49 /*
50 HAnim examples:
51 http://www.web3d.org/x3d/content/examples/Basic/HumanoidAnimation/
52  Octaga InstantReality
53 - BoxMan.x3d good doesn't animate
54 - AllenDutton.x3d skin stuck good
55 - NancyStandShootRifleM24.x3d good anim good, skin bad
56 - (KelpForest) NancyDiving.x3d good good
57 HAnim Prototypes:
58 http://www.web3d.org/x3d/content/examples/Basic/HumanoidAnimation/_pages/page11.html
59 HAnim examples:
60 http://www.web3d.org/x3d/content/examples/Basic/#HumanoidAnimation
61 Specs:
62 http://www.web3d.org/documents/specifications/19775-1/V3.3/Part01/components/hanim.html
63 These specs don't articulate the field meanings, instead point to an ISO doc:
64 http://www.iso.org/iso/home/store/catalogue_tc/catalogue_detail.htm?csnumber=33912
65 I19774 about $80
66 Here's some free online docs:
67 http://www.h-anim.org/
68 http://h-anim.org/Specifications/H-Anim200x/ISO_IEC_FCD_19774/
69 http://h-anim.org/Specifications/H-Anim200x/ISO_IEC_FCD_19774/ObjectInterfaces.html
70 - Humanoid has transform, skeleton, skin, (flat lists of) skinCoord, skinNormal, segments,joints,sites,viewpoints
71 - Joint has transform, children, displacers, skinCoord indx,wt
72 - Segment has children, displacers, mass, coord
73 - Site has transform, children
74 - Displacer has displacements, coord, wt, coord index,
75 All the fields are discussed.
76 
77 July 2016
78 - where we left off years ago?
79 - define HANIMHANIM below to compile - lots of errors
80 Nov 2016
81 - stack errors fixed by removing return; at top of some functions
82 x but doesn't render/animate correctly: whole body frozen, various limbs moving independently/dismembered
83 
84 Related Links on HAnim
85 http://www.web3d.org/working-groups/humanoid-animation-h-anim
86 - The tutorial
87 Links on character animation for real-time graphics:
88 http://www.cescg.org/CESCG-2002/MPutzKHufnagl/paper.pdf
89 - Character Animation for Real-time Applications
90 http://apc.dcti.iscte.pt/praticas/Real-Time%20Character%20Animation%20for%20Computer%20Games.pdf
91 - (Anderson) Real-Time Character Animation for Computer Games
92 https://books.google.ca/books?id=O0sxtDeT5PEC&pg=PA125&lpg=PA125&dq=Animating+single+mesh+character+in+real+time&source=bl&ots=u8gETEoSM0&sig=AW7nQB25K4IxjZp_7xSlLJRxiCQ&hl=en&sa=X&ved=0ahUKEwiQ6NHdoarOAhVX2mMKHVrdDR8Q6AEIJjAB#v=onepage&q=Animating%20single%20mesh%20character%20in%20real%20time&f=false
93 - book: Real-time Character Animation with Visual C++
94 - shows additive approach to vertex blending:
95  vertex {
96  xyz original;
97  xyz world;
98  int number_of_limbs_influencing;
99  }
100  set number_of_limbs influencing vertex;
101  on each frame,
102  zero worlds
103  Iterate over limbs, transforming originals influenced and adding/summing onto worlds.
104  divide each world by number_of_limbs
105 http://www.nvidia.com/object/doc_characters.html
106 - Nvidia link page for various game programming algos with gpu acceleration
107 http://ruh.li/AnimationVertexSkinning.html
108 - Skinning shader
109 http://http.developer.nvidia.com/GPUGems/gpugems_ch04.html
110 - Bind pose, dawn
111 http://www.3dgep.com/gpu-skinning-of-md5-models-in-opengl-and-cg/
112 - Glsl impl of skinning
113 http://tech-artists.org/wiki/Vertex_Skinning
114 - ogre sample shader
115 https://www.cs.tcd.ie/publications/tech-reports/reports.06/TCD-CS-2006-46.pdf
116 - dual quat skinning
117 
118 
119 Q if the skeleton isnt rendered, when would you traverse the skeleton
120 And whats the output?
121 Q isnt there some kind of ik solver that could/should be exposed to sai as a node?
122 Otherwise you will need compiled/fast scrpt engine if its all in js, and
123 scene authors will need to know all that stuff.
124 https://en.wikipedia.org/wiki/Inverse_kinematics
125 https://en.wikipedia.org/wiki/Moment_of_inertia
126 dug9 july 2016: What's Weird about HAnim:
127 a) looks like there's very little animation work we have to do in our browser
128  the scene author has to do it all in js / via SAI
129 b) the skeleton isn't rendered (if no geom on sites/segments?)
130  so when do you traverse the joints and what's the output?
131 
132 dug9 aug 2016: would this work:
133 Just render_HAnimHumanoid (as un-shared/opaque private scenegraph?)
134 - traverse the joints and segments privately from HanimHumanoid to call their render_ functions
135 - no HanimHumanoid? then don't render any joints or segments - don't list virtual functions for them
136 
137 Design Options:
138 1. 2-step
139 a) interpolate the pose of joints and segments relative to HanimHumanoid
140  i) start with Identity transform at HanimHumanoid
141  ii) traverse down segments and joints, and sites, pushing, multiplying and saving
142  the cumulative transform in each segment/joint/site
143 b) for each segment/joint/site (done at the HanimHumanoid level)
144  i) push cumulative pose for segment/joint/site onto transform stack
145  ii) render any attached geometry via noralchildren
146 2. Combined step
147 a) traverse down segments pushing and multiplying pose
148 b) when visiting a segment/joint/site render its children geometry
149  x this wont work with skin/'skinning', just attached solid geometry ie scuba tank
150  * so instead of the 'render' step for skin, there would be vertex-update step
151 3. Best Guess
152 a) traverse skeleton joints rendering attached solid geometry, and updating influenced skin vertices
153 b) divide skin vertices by number of influencers
154 c) render skin
155 
156 Requirements:
157 - single deformable mesh should be 'easy' / possible / efficient to update / interpolate
158 
159 How to update single deformable mesh?
160 Please research, as its a common thing in game programming.
161 Guesses:
162 - do we have/could we have a system for interpolating the compiled polyrep?
163 - for example if during compiling the polyrep we kept an expanded index,
164  so a vertex index stored in a joint could find all the triangle vertices in the compiled / tesselated / triangulated mesh?
165  array[original index] [list of compiled polyrep vertex indexes]
166 - or when compiling the HAnimHumanoid, would/could we break the polyrep into chunks associated with segments
167  based on 3D proximity
168 - or would we transform the whole mesh for each segment, except weight the points differently,
169  so that the final mesh is a per-vertex-weighted sum of all segment meshes
170 
171 Nov 2016
172 state Nov 3, 2016:
173 NancyDiving.x3d (scene :HanimHumanoid(HH) with
174  HH->Skeleton children[ RootJoint, Joints, Segments] and
175  HH->joints, HH->segments
176  no HH->skin,->viewpoints
177 x I don't see a single skin mesh/vertices being updated by weighted transforms
178 x I don't see any mention of Displacer node type
179 H: its a LOA 0 (or lowest level, with separate segments for each limb)
180 
181 freewrl
182 x I don't see a single skin mesh vertices being updated by weighted transforms in code below
183 x I don't see any mention of Displacer node type below, although its in perl/structs.h
184 H:
185 it was put together quickly using boilerplate scenegraph calls, for LOA 0,
186 but without detailed custom code or testing to make it work for LOA 1+
187 
188 freewrl rendering of NancyDiving.x3d
189 x skin frozen, while indvidual body segments are transformed separately / dismembered,
190 x seem to be missing rotations on the segments
191 FIXED for LOA-0 ie NancyDiving.x3d
192 
193 Nov 5, 2016
194 Need to add .skin weighted vertex blending for LOA-1 ie BoxMan.x3d
195 2 methods:
196 CPU - transform coords on CPU side, try to do without re-compiling shape node as a result of change
197  a) stream_polyrep actualcoord update based on tesselation indexes, for glDrawArray
198  b) replace stream_polyrep with new stream_indexed so child_shape renders via glDrawElements
199  then less processing to update vertices which are kept 1:1 with original
200 GPU - as with CPU a) or b), except:
201  jointTransforms JT[] are sent to gpu, with index and weight as vertex attributes
202  https://www.opengl.org/wiki/Skeletal_Animation
203 
204 How it would all work
205 on child_humanoid rendering call:
206 - clear a list of per-skinCoord-vertex indexs PSVI[] and weights PSVW[] size = skinCoord.n
207 - clear a flat list of transforms, [] size ~= number of joints
208 - clear a stack of humanoid transforms
209 - render skeleton
210  for each Joint
211  aggregate humanoid transform like we normally do
212  GPU method:
213  parse xyz and quaternion from the matrix (is that possible/easy? do I have code?)
214  add {xyz,quaternion} joint transform to joint transform list JT[], get its new index JI
215  CPU method
216  add cumulative humanoid joint transform to joint transform list JT[], get its new index JI
217  iterate over joint's list of coordIndices, and for each index
218  add the jointTransformIndex JI to PSVI[index]
219  add the jointWeight to go with the index PSVW[index] = wt
220  for each sites or segment - render as normal scenegraph content
221 - render skin
222  GPU method: set skeletal animation vertex blending shader flag SKELETAL on shaderflags stack
223  CPU method: copy and do weighted transform of coords here using PSVI, PSVW
224  for each shape in skin:
225  draw as normal shape, almost, except:
226  GPU method: send (untransformed) coordinates to shader as vertices as usual
227  CPU method: if SKELETAL && CPU substitute transformed coords, and send to shader
228  for drawElements, send indices
229  if SKELETAL && GPU, then, after compiling/fetching shader:
230  send list of jointtransforms to shader as array(s) of vec4
231  send indexes to JTs to shader as vertex attributes
232  send weights to shader as vertex attributes
233  in shader if SKELETAL && GPU
234  apply weighted transforms
235 
236 
237 */
238 
239 
240 /* last HAnimHumanoid skinCoord and skinNormals */
241 //void *HANimSkinCoord = 0;
242 //void *HAnimSkinNormal = 0;
243 typedef struct pComponent_HAnim{
244  struct X3D_HAnimHumanoid *HH;
245  double HHMatrix[16];
246 
248 void *Component_HAnim_constructor(){
249  void *v = MALLOCV(sizeof(struct pComponent_HAnim));
250  memset(v,0,sizeof(struct pComponent_HAnim));
251  return v;
252 }
253 void Component_HAnim_init(struct tComponent_HAnim *t){
254  //public
255  //private
256  t->prv = Component_HAnim_constructor();
257  {
259  p->HH = NULL;
260 
261  }
262 }
263 void Component_HAnim_clear(struct tComponent_HAnim *t){
264  //public
265  //private
266  {
267  //ppComponent_HAnim p = (ppComponent_HAnim)t->prv;
268  }
269 }
270 //ppComponent_HAnim p = (ppComponent_HAnim)gglobal()->Component_HAnim.prv;
271 
272 
273 void compile_HAnimJoint (struct X3D_HAnimJoint *node){
274 
275  INITIALIZE_EXTENT;
276 
277  /* printf ("changed Transform for node %u\n",node); */
278  node->__do_center = verify_translate ((GLfloat *)node->center.c);
279  node->__do_trans = verify_translate ((GLfloat *)node->translation.c);
280  node->__do_scale = verify_scale ((GLfloat *)node->scale.c);
281  node->__do_rotation = verify_rotate ((GLfloat *)node->rotation.c);
282  node->__do_scaleO = verify_rotate ((GLfloat *)node->scaleOrientation.c);
283 
284  node->__do_anything = (node->__do_center ||
285  node->__do_trans ||
286  node->__do_scale ||
287  node->__do_rotation ||
288  node->__do_scaleO);
289 
290  //REINITIALIZE_SORTED_NODES_FIELD(node->children,node->_sortedChildren);
291  MARK_NODE_COMPILED
292 
293 }
294 void prep_HAnimJoint (struct X3D_HAnimJoint *node) {
295 
296 
297 
298  COMPILE_IF_REQUIRED
299 
300  /* rendering the viewpoint means doing the inverse transformations in reverse order (while poping stack),
301  * so we do nothing here in that case -ncoder */
302 
303  /* printf ("prep_Transform, render_hier vp %d geom %d light %d sens %d blend %d prox %d col %d\n",
304  render_vp,render_geom,render_light,render_sensitive,render_blend,render_proximity,render_collision); */
305 
306  /* do we have any geometry visible, and are we doing anything with geometry? */
307  //OCCLUSIONTEST
308 
309  if(!renderstate()->render_vp) {
310  /* do we actually have any thing to rotate/translate/scale?? */
311  if (node->__do_anything) {
312 
313  FW_GL_PUSH_MATRIX();
314 
315  /* TRANSLATION */
316  if (node->__do_trans)
317  FW_GL_TRANSLATE_F(node->translation.c[0],node->translation.c[1],node->translation.c[2]);
318 
319  /* CENTER */
320  if (node->__do_center)
321  FW_GL_TRANSLATE_F(node->center.c[0],node->center.c[1],node->center.c[2]);
322 
323  /* ROTATION */
324  if (node->__do_rotation) {
325  FW_GL_ROTATE_RADIANS(node->rotation.c[3], node->rotation.c[0],node->rotation.c[1],node->rotation.c[2]);
326  }
327 
328  /* SCALEORIENTATION */
329  if (node->__do_scaleO) {
330  FW_GL_ROTATE_RADIANS(node->scaleOrientation.c[3], node->scaleOrientation.c[0], node->scaleOrientation.c[1],node->scaleOrientation.c[2]);
331  }
332 
333 
334  /* SCALE */
335  if (node->__do_scale)
336  FW_GL_SCALE_F(node->scale.c[0],node->scale.c[1],node->scale.c[2]);
337 
338  /* REVERSE SCALE ORIENTATION */
339  if (node->__do_scaleO)
340  FW_GL_ROTATE_RADIANS(-node->scaleOrientation.c[3], node->scaleOrientation.c[0], node->scaleOrientation.c[1],node->scaleOrientation.c[2]);
341 
342  /* REVERSE CENTER */
343  if (node->__do_center)
344  FW_GL_TRANSLATE_F(-node->center.c[0],-node->center.c[1],-node->center.c[2]);
345  }
346 
347  RECORD_DISTANCE
348 
349  }
350 
351 }
352 
353 
354 void fin_HAnimJoint (struct X3D_HAnimJoint *node) {
355 
356  OCCLUSIONTEST
357 
358  if(!renderstate()->render_vp) {
359  if (node->__do_anything) {
360  FW_GL_POP_MATRIX();
361  }
362  } else {
363  /*Rendering the viewpoint only means finding it, and calculating the reverse WorldView matrix.*/
364  if((node->_renderFlags & VF_Viewpoint) == VF_Viewpoint) {
365  FW_GL_TRANSLATE_F(((node->center).c[0]),((node->center).c[1]),((node->center).c[2])
366  );
367  FW_GL_ROTATE_RADIANS(((node->scaleOrientation).c[3]),((node->scaleOrientation).c[0]),((node->scaleOrientation).c[1]),((node->scaleOrientation).c[2])
368  );
369  FW_GL_SCALE_F((float)1.0/(((node->scale).c[0])),(float)1.0/(((node->scale).c[1])),(float)1.0/(((node->scale).c[2]))
370  );
371  FW_GL_ROTATE_RADIANS(-(((node->scaleOrientation).c[3])),((node->scaleOrientation).c[0]),((node->scaleOrientation).c[1]),((node->scaleOrientation).c[2])
372  );
373  FW_GL_ROTATE_RADIANS(-(((node->rotation).c[3])),((node->rotation).c[0]),((node->rotation).c[1]),((node->rotation).c[2])
374  );
375  FW_GL_TRANSLATE_F(-(((node->center).c[0])),-(((node->center).c[1])),-(((node->center).c[2]))
376  );
377  FW_GL_TRANSLATE_F(-(((node->translation).c[0])),-(((node->translation).c[1])),-(((node->translation).c[2]))
378  );
379  }
380  }
381 
382 }
383 
384 void compile_HAnimSite (struct X3D_HAnimSite *node){
385 
386  INITIALIZE_EXTENT;
387 
388  /* printf ("changed Transform for node %u\n",node); */
389  node->__do_center = verify_translate ((GLfloat *)node->center.c);
390  node->__do_trans = verify_translate ((GLfloat *)node->translation.c);
391  node->__do_scale = verify_scale ((GLfloat *)node->scale.c);
392  node->__do_rotation = verify_rotate ((GLfloat *)node->rotation.c);
393  node->__do_scaleO = verify_rotate ((GLfloat *)node->scaleOrientation.c);
394 
395  node->__do_anything = (node->__do_center ||
396  node->__do_trans ||
397  node->__do_scale ||
398  node->__do_rotation ||
399  node->__do_scaleO);
400 
401  //REINITIALIZE_SORTED_NODES_FIELD(node->children,node->_sortedChildren);
402  MARK_NODE_COMPILED
403 
404 }
405 void prep_HAnimSite (struct X3D_HAnimSite *node) {
406 
407 
408 
409  COMPILE_IF_REQUIRED
410 
411  /* rendering the viewpoint means doing the inverse transformations in reverse order (while poping stack),
412  * so we do nothing here in that case -ncoder */
413 
414  /* printf ("prep_Transform, render_hier vp %d geom %d light %d sens %d blend %d prox %d col %d\n",
415  render_vp,render_geom,render_light,render_sensitive,render_blend,render_proximity,render_collision); */
416 
417  /* do we have any geometry visible, and are we doing anything with geometry? */
418  //OCCLUSIONTEST
419 
420  if(!renderstate()->render_vp) {
421  /* do we actually have any thing to rotate/translate/scale?? */
422  if (node->__do_anything) {
423 
424  FW_GL_PUSH_MATRIX();
425 
426  /* TRANSLATION */
427  if (node->__do_trans)
428  FW_GL_TRANSLATE_F(node->translation.c[0],node->translation.c[1],node->translation.c[2]);
429 
430  /* CENTER */
431  if (node->__do_center)
432  FW_GL_TRANSLATE_F(node->center.c[0],node->center.c[1],node->center.c[2]);
433 
434  /* ROTATION */
435  if (node->__do_rotation) {
436  FW_GL_ROTATE_RADIANS(node->rotation.c[3], node->rotation.c[0],node->rotation.c[1],node->rotation.c[2]);
437  }
438 
439  /* SCALEORIENTATION */
440  if (node->__do_scaleO) {
441  FW_GL_ROTATE_RADIANS(node->scaleOrientation.c[3], node->scaleOrientation.c[0], node->scaleOrientation.c[1],node->scaleOrientation.c[2]);
442  }
443 
444 
445  /* SCALE */
446  if (node->__do_scale)
447  FW_GL_SCALE_F(node->scale.c[0],node->scale.c[1],node->scale.c[2]);
448 
449  /* REVERSE SCALE ORIENTATION */
450  if (node->__do_scaleO)
451  FW_GL_ROTATE_RADIANS(-node->scaleOrientation.c[3], node->scaleOrientation.c[0], node->scaleOrientation.c[1],node->scaleOrientation.c[2]);
452 
453  /* REVERSE CENTER */
454  if (node->__do_center)
455  FW_GL_TRANSLATE_F(-node->center.c[0],-node->center.c[1],-node->center.c[2]);
456  }
457 
458  RECORD_DISTANCE
459 
460  }
461 
462 }
463 
464 
465 void fin_HAnimSite (struct X3D_HAnimSite *node) {
466 
467  OCCLUSIONTEST
468 
469  if(!renderstate()->render_vp) {
470  if (node->__do_anything) {
471  FW_GL_POP_MATRIX();
472  }
473  } else {
474  /*Rendering the viewpoint only means finding it, and calculating the reverse WorldView matrix.*/
475  if((node->_renderFlags & VF_Viewpoint) == VF_Viewpoint) {
476  FW_GL_TRANSLATE_F(((node->center).c[0]),((node->center).c[1]),((node->center).c[2])
477  );
478  FW_GL_ROTATE_RADIANS(((node->scaleOrientation).c[3]),((node->scaleOrientation).c[0]),((node->scaleOrientation).c[1]),((node->scaleOrientation).c[2])
479  );
480  FW_GL_SCALE_F((float)1.0/(((node->scale).c[0])),(float)1.0/(((node->scale).c[1])),(float)1.0/(((node->scale).c[2]))
481  );
482  FW_GL_ROTATE_RADIANS(-(((node->scaleOrientation).c[3])),((node->scaleOrientation).c[0]),((node->scaleOrientation).c[1]),((node->scaleOrientation).c[2])
483  );
484  FW_GL_ROTATE_RADIANS(-(((node->rotation).c[3])),((node->rotation).c[0]),((node->rotation).c[1]),((node->rotation).c[2])
485  );
486  FW_GL_TRANSLATE_F(-(((node->center).c[0])),-(((node->center).c[1])),-(((node->center).c[2]))
487  );
488  FW_GL_TRANSLATE_F(-(((node->translation).c[0])),-(((node->translation).c[1])),-(((node->translation).c[2]))
489  );
490  }
491  }
492 
493 }
494 
495 typedef struct {
496  double mat [16];
497  float normat[9];
498 } JMATRIX;
499 enum {
500  VERTEXTRANSFORMMETHOD_CPU = 1,
501  VERTEXTRANSFORMMETHOD_GPU = 2,
502 };
503 static int vertexTransformMethod = VERTEXTRANSFORMMETHOD_CPU;
504 void render_HAnimHumanoid (struct X3D_HAnimHumanoid *node) {
505  /* save the skinCoords and skinNormals for use in following HAnimJoints */
506  /* printf ("rendering HAnimHumanoid\n"); */
507 }
508 
509 void render_HAnimJoint (struct X3D_HAnimJoint * node) {
510  int i,j, jointTransformIndex;
511  double modelviewMatrix[16]; //, mvmInverse[16];
512  JMATRIX jointMatrix;
513  Stack *JT;
514  float *PVW, *PVI;
515 
516  ppComponent_HAnim p = (ppComponent_HAnim)gglobal()->Component_HAnim.prv;
517  //printf ("rendering HAnimJoint %d\n",node);
518 
519 
520  JT = p->HH->_JT;
521 
522  //step 1, generate transform
523  FW_GL_GETDOUBLEV(GL_MODELVIEW_MATRIX, modelviewMatrix);
524  matmultiplyAFFINE(jointMatrix.mat,modelviewMatrix,p->HHMatrix);
525  if(p->HH->skinNormal){
526  //want 'inverse-transpose' 3x3 float for transforming normals
527  //(its almost the same as jointMatrix.mat except when shear due to assymetric scales)
528  float fmat4[16], fmat3[9],fmat3i[9]; //,fmat3it[9];
529  matdouble2float4(fmat4,jointMatrix.mat);
530  mat423f(fmat3,fmat4);
531  matinverse3f(fmat3i,fmat3);
532  mattranspose3f(jointMatrix.normat,fmat3i);
533  //printf("jm.normat[1] %f\n",jointMatrix.normat[1]);
534  }
535 
536  if(vertexTransformMethod == VERTEXTRANSFORMMETHOD_GPU){
537  //convert to quaternion + position
538  //add to HH transform list
539  }else if(vertexTransformMethod == VERTEXTRANSFORMMETHOD_CPU){
540  //step 2, add transform to HH transform list, get its index in list
541  stack_push(JMATRIX,JT,jointMatrix);
542  }
543  //I'll let this index start at 1, and subtract 1 when retrieving with vector_get,
544  //so I can use jointTransformIndex==0 as a sentinal value for 'no transform stored'
545  //to save me from having an extra .n transforms variable
546  jointTransformIndex = vectorSize(JT);
547 
548  //step 3, add transform index and weight to each skin vertex
549  PVW = (float*)p->HH->_PVW;
550  PVI = (float*)p->HH->_PVI;
551  for(i=0;i<node->skinCoordIndex.n;i++){
552  int idx = node->skinCoordIndex.p[i];
553  float wt = node->skinCoordWeight.p[min(i,node->skinCoordWeight.n -1)];
554  for(j=0;j<4;j++){
555  if(PVI[idx*4 + j] == 0.0f){
556  PVI[idx*4 +j] = (float)jointTransformIndex;
557  PVW[idx*4 +j] = wt;
558  }
559  }
560  }
561  //step 4: add on any Displacer displacements
562  if(p->HH->skinCoord && node->displacers.n ){
563  int ni, i;
564  float *psc, *pdp;
565  int *ci;
566  struct X3D_Coordinate *nc = (struct X3D_Coordinate*)p->HH->skinCoord;
567  psc = (float*)nc->point.p;
568  // nsc = nc->point.n;
569  for(i=0;i<node->displacers.n;i++){
570  int index, j;
571  float *point, weight, wdisp[3];
572  struct X3D_HAnimDisplacer *dp = (struct X3D_HAnimDisplacer *)node->displacers.p[i];
573 
574  weight = dp->weight;
575  //printf(" %f ",weight);
576  pdp = (float*)dp->displacements.p;
577  // ndp = dp->displacements.n;
578 
579  ni = dp->coordIndex.n;
580  ci = dp->coordIndex.p;
581  for(j=0;j<ni;j++){
582  index = ci[j];
583  point = &psc[index*3];
584  vecscale3f(wdisp,&pdp[j*3],weight);
585  vecadd3f(point,point,wdisp);
586  }
587  }
588  if(0){ //this is done in child_HAnimHumanoid for the skinCoord parents
589  //force HAnimSegment.children[] shape nodes using segment->coord to recompile
590  int k;
591  Stack *parents;
592  p->HH->skinCoord->_change++;
593  parents = p->HH->skinCoord->_parentVector;
594  for(k=0;k<vectorSize(parents);k++){
595  struct X3D_Node *parent = vector_get(struct X3D_Node*,parents,k);
596  parent->_change++;
597  }
598  }
599 
600  }
601 
602 }
603 int vecsametol3f(float *a, float *b, float tol){
604  int i,isame = TRUE;
605  for(i=0;i<3;i++)
606  if(fabsf(a[i] - b[i]) > tol) isame = FALSE;
607  return isame;
608 }
609 void compile_HAnimHumanoid(struct X3D_HAnimHumanoid *node){
610  //printf("compile_HAnimHumanoid\n");
611  //check if the coordinate count is the same
612  int nsc = 0, nsn = 0;
613  float *psc = NULL, *psn = NULL;
614  if(node->skinCoord && node->skinCoord->_nodeType == NODE_Coordinate){
615  struct X3D_Coordinate * nc = (struct X3D_Coordinate * )node->skinCoord;
616  nsc = nc->point.n;
617  psc = (float*)nc->point.p;
618  node->_origCoords = realloc(node->_origCoords,nsc*3*sizeof(float));
619  memcpy(node->_origCoords,psc,nsc*3*sizeof(float));
620  if(0){
621  //find a few coordinates in skinCoord I hacked, by xyz, and give me their index, for making a displacer
622  float myfind[9] = {-0.030000f, -0.070000f, 1.777000f, -0.070000f, 1.777000f, 0.130000f, 1.777000f, 0.130000f, 0.070000f };
623  int i,j;
624  for(i=0;i<nsc;i++){
625  for(j=0;j<3;j++)
626  if(vecsametol3f(&psc[i*3],&myfind[j*3],.001f)){
627  printf("%d %f %f %f\n",i,myfind[j*3 + 0],myfind[j*3 +1],myfind[j*3 +2]);
628  }
629  }
630  }
631  }
632  if(node->skinNormal && node->skinNormal->_nodeType == NODE_Normal){
633  struct X3D_Normal * nn = (struct X3D_Normal * )node->skinNormal;
634  //Assuming 1 normal per coord, coord 1:1 normal
635  nsn = nn->vector.n;
636  psn = (float*)nn->vector.p;
637  node->_origNorms = realloc(node->_origNorms,nsn*3*sizeof(float));
638  memcpy(node->_origNorms,psn,nsn*3*sizeof(float));
639  }
640 
641  //allocate the joint-transform_index and joint-weight arrays
642  //Nov 2016: max 4: meaning each skinCoord can have up to 4 joints referencing/influencing it
643  //4 chosen so it's easier to port to GPU method with vec4
644  if(node->_NV == 0 || node->_NV != nsc){
645  node->_PVI = realloc(node->_PVI,nsc*4*sizeof(float)); //indexes, up to 4 joints per skinCoord
646  node->_PVW = realloc(node->_PVW,nsc*4*sizeof(float)); //weights, up to 4 joints per skinCoord
647  node->_NV = nsc;
648  }
649  //allocate the transform array
650  if(node->_JT == NULL) {
651  if(vertexTransformMethod == VERTEXTRANSFORMMETHOD_GPU){
652  //new stack quat + position
653  }else if(vertexTransformMethod == VERTEXTRANSFORMMETHOD_CPU){
654  node->_JT = newStack(JMATRIX); //we don't know how many joints there are - need to count as we go
655  }
656  }
657  MARK_NODE_COMPILED
658 }
659 
660 void child_HAnimHumanoid(struct X3D_HAnimHumanoid *node) {
661  int nc;
662  //float *originalCoords;
663  Stack *JT;
664  ppComponent_HAnim p = (ppComponent_HAnim)gglobal()->Component_HAnim.prv;
665  COMPILE_IF_REQUIRED
666 
667  //LOCAL_LIGHT_SAVE
668 
669  /* any segments at all? */
670 /*
671 printf ("hanimHumanoid, segment coutns %d %d %d %d %d %d\n",
672  node->joints.n,
673  node->segments.n,
674  node->sites.n,
675  node->skeleton.n,
676  node->skin.n,
677  node->viewpoints.n);
678 */
679 
680  nc = node->joints.n + node->segments.n + node->viewpoints.n + node->sites.n +
681  node->skeleton.n + node->skin.n;
682 
683  RETURN_FROM_CHILD_IF_NOT_FOR_ME
684 
685  if(renderstate()->render_vp){
686  /* Lets do viewpoints */
687  normalChildren(node->viewpoints);
688  return;
689  }
690 
691 
692  // segments, joints, sites are flat-lists for convenience
693  // skeleton is the scenegraph-like transform hierarchy of joints and segments and sites
694  // skin relies on something updating its vertices based on skeleton transforms
695  /* Lets do segments first */
696  /* now, just render the non-directionalLight segments */
697  if(0) normalChildren(node->segments);
698 
699 
700  /* Lets do joints second */
701  /* do we have to sort this node? */
702  /* now, just render the non-directionalLight joints */
703  if(0) normalChildren(node->joints);
704 
705 
706  /* Lets do sites third */
707  /* do we have to sort this node? */
708  /* do we have a local light for a child? */
709  //LOCAL_LIGHT_CHILDREN(node->sites);
710  /* now, just render the non-directionalLight sites */
711  if(0) normalChildren(node->sites);
712 
713  prep_sibAffectors((struct X3D_Node*)node,&node->__sibAffectors);
714  /* Lets do skeleton fourth */
715  /* do we have to sort this node? */
716  /* now, just render the non-directionalLight skeleton */
717  //skeleton is the basic thing to render for LOA 0
718  memset(node->_PVI,0,4*node->_NV*sizeof(float));
719  memset(node->_PVW,0,4*node->_NV*sizeof(float));
720  JT = node->_JT;
721  JT->n = 0;
722 
723  //in theory, HH, HHMatrix could be a stack, so you could have an hanimhumaoid within an hanimhunaniod
724  p->HH = node;
725  {
726  double modelviewMatrix[16];
727  FW_GL_GETDOUBLEV(GL_MODELVIEW_MATRIX, modelviewMatrix);
728  matinverseAFFINE(p->HHMatrix,modelviewMatrix);
729  }
730  if(node->skin.n){
731  if(vertexTransformMethod == VERTEXTRANSFORMMETHOD_CPU){
732  //save original coordinates before rendering skeleton
733  // - HAnimJoint may have displacers that change the Coords
734  //transform each vertex and its normal using weighted transform
735  int nsc = 0, nsn = 0;
736  float *psc = NULL, *psn = NULL;
737  if(node->skinCoord && node->skinCoord->_nodeType == NODE_Coordinate){
738  struct X3D_Coordinate * nc = (struct X3D_Coordinate * )node->skinCoord;
739  struct X3D_Normal *nn = (struct X3D_Normal *)node->skinNormal; //might be NULL
740  nsc = nc->point.n;
741  psc = (float*)nc->point.p;
742  memcpy(psc,node->_origCoords,3*nsc*sizeof(float));
743  if(nn){
744  nsn = nn->vector.n;
745  psn = (float *)nn->vector.p;
746  memcpy(psn,node->_origNorms,3*nsn*sizeof(float));
747  }
748  }
749  }
750  }
751  if(1) normalChildren(node->skeleton);
752 
753  if(node->skin.n){
754  if(vertexTransformMethod == VERTEXTRANSFORMMETHOD_CPU){
755  //save original coordinates
756  //transform each vertex and its normal using weighted transform
757  int i,j,nsc = 0;
758  // int nsn = 0;
759  float *psc = NULL, *psn = NULL;
760  if(node->skinCoord && node->skinCoord->_nodeType == NODE_Coordinate){
761  struct X3D_Coordinate * nc = (struct X3D_Coordinate * )node->skinCoord;
762  struct X3D_Normal *nn = (struct X3D_Normal *)node->skinNormal; //might be NULL
763  nsc = nc->point.n;
764  psc = (float*)nc->point.p;
765  //memcpy(psc,node->_origCoords,3*nsc*sizeof(float));
766  if(nn){
767  // nsn = nn->vector.n;
768  psn = (float *)nn->vector.p;
769  //memcpy(psn,node->_origNorms,3*nsn*sizeof(float));
770  }
771 
772  for(i=0;i<nsc;i++){
773  float totalWeight;
774  float *point, *norm;
775  float newpoint[3], newnorm[3];
776  float *PVW, *PVI;
777 
778  point = &psc[i*3];
779  norm = NULL;
780  if(nn) norm = &psn[i*3];
781  PVW = node->_PVW;
782  PVI = node->_PVI;
783 
784  memset(newpoint,0,3*sizeof(float));
785  memset(newnorm,0,3*sizeof(float));
786  totalWeight = 0.0f;
787  for(j=0;j<4;j++){
788  int jointTransformIndex = (int)PVI[i*4 + j];
789  float wt = PVW[i*4 + j];
790  if(jointTransformIndex > 0){
791  float tpoint[3], tnorm[3];
792  JMATRIX jointMatrix;
793  jointMatrix = vector_get(JMATRIX,node->_JT,jointTransformIndex -1);
794  transformf(tpoint,point,jointMatrix.mat);
795  vecscale3f(tpoint,tpoint,wt);
796  vecadd3f(newpoint,newpoint,tpoint);
797  if(nn){
798  transform3x3f(tnorm,norm,jointMatrix.normat);
799  vecnormalize3f(tnorm,tnorm);
800  vecscale3f(tnorm,tnorm,wt);
801  vecadd3f(newnorm,newnorm,tnorm);
802  }
803  totalWeight += wt;
804  }
805  }
806  if(totalWeight > 0.0f){
807  vecscale3f(newpoint,newpoint,1.0f/totalWeight);
808  veccopy3f(point,newpoint);
809  if(nn){
810  vecscale3f(newnorm,newnorm,1.0f/totalWeight);
811  vecnormalize3f(norm,newnorm);
812  }
813  }
814  }
815  if(0){
816  //print out before and after coords
817  float *osc = node->_origCoords;
818  for(i=0;i<nsc;i++){
819  printf("%d ",i);
820  for(j=0;j<3;j++) printf("%f ",psc[i*3 +j]);
821  printf("/ ");
822  for(j=0;j<3;j++) printf("%f ",osc[i*3 +j]);
823  printf("\n");
824  }
825  printf("\n");
826  }
827  //trigger recompile of skin->shapes when rendering skin
828  //Nov 6, 2016: recompiling a shape / polyrep on each frame eats memory
829  //NODE_NEEDS_COMPILING
830  if(1){
831  int k;
832  Stack *parents;
833  node->skinCoord->_change++;
834  parents = node->skinCoord->_parentVector;
835  for(k=0;k<vectorSize(parents);k++){
836  struct X3D_Node *parent = vector_get(struct X3D_Node*,parents,k);
837  parent->_change++;
838  }
839  }
840 
841  }
842  }else if(vertexTransformMethod == VERTEXTRANSFORMMETHOD_GPU){
843  //push shader flaga with += SKELETAL
844  }
845 
846  if(1) normalChildren(node->skin);
847  if(vertexTransformMethod == VERTEXTRANSFORMMETHOD_GPU){
848  //pop shader flags
849  } else if(vertexTransformMethod == VERTEXTRANSFORMMETHOD_CPU){
850  //restore original coordinates
851  int nsc, nsn;
852  float *psc, *psn;
853  struct X3D_Coordinate * nc = (struct X3D_Coordinate * )node->skinCoord;
854  struct X3D_Normal * nn = (struct X3D_Normal * )node->skinNormal;
855  nsc = nc->point.n;
856  psc = (float*)nc->point.p;
857  memcpy(psc,node->_origCoords,3*nsc*sizeof(float));
858  if(nn){
859  nsn = nn->vector.n;
860  psn = (float*)nn->vector.p;
861  memcpy(psn,node->_origNorms,3*nsn*sizeof(float));
862  }
863  }
864  } //if skin
865  fin_sibAffectors((struct X3D_Node*)node,&node->__sibAffectors);
866 
867 
868  /* did we have that directionalLight? */
869  //LOCAL_LIGHT_OFF
870 }
871 
872 
873 void child_HAnimJoint(struct X3D_HAnimJoint *node) {
874 
875  //CHILDREN_COUNT
876  /* any children at all? */
877  //if (nc==0) return;
878 
879  /* should we go down here? */
880  //RETURN_FROM_CHILD_IF_NOT_FOR_ME
881 
882  /* do we have to sort this node? */
883 
884  /* just render the non-directionalLight children */
885  normalChildren(node->children);
886 
887 
888 }
889 float *vecmix3f(float *out3, float* a3, float *b3, float fraction){
890  int i;
891  for(i=0;i<3;i++){
892  out3[i] = (1.0f - fraction)*a3[i] + fraction*b3[i];
893  }
894  return out3;
895 }
896 void child_HAnimSegment(struct X3D_HAnimSegment *node) {
897 
898  //CHILDREN_COUNT
899 
900 
901 //note to implementer: have to POSSIBLE_PROTO_EXPANSION(node->coord, tmpN)
902 
903  /* any children at all? */
904  //if (nc==0) return;
905 
906  /* should we go down here? */
907  //RETURN_FROM_CHILD_IF_NOT_FOR_ME
908 
909  /* do we have to sort this node? Only if not a proto - only first node has visible children. */
910 
911  /* now, just render the non-directionalLight children */
912  if(node->coord && node->displacers.n){
913 
914  int nsc, ni, i;
915  float *psc, *pdp;
916  int *ci;
917  struct X3D_Coordinate *nc = (struct X3D_Coordinate*)node->coord;
918  psc = (float*)nc->point.p;
919  nsc = nc->point.n;
920  if(!node->_origCoords)
921  node->_origCoords = malloc(3*nsc*sizeof(float));
922  memcpy(node->_origCoords,psc,3*nsc*sizeof(float));
923  for(i=0;i<node->displacers.n;i++){
924  int index, j;
925  float *point, weight, wdisp[3];
926  struct X3D_HAnimDisplacer *dp = (struct X3D_HAnimDisplacer *)node->displacers.p[i];
927 
928  weight = dp->weight;
929  //printf(" %f ",weight);
930  pdp = (float*)dp->displacements.p;
931  // ndp = dp->displacements.n;
932 
933  ni = dp->coordIndex.n;
934  ci = dp->coordIndex.p;
935  for(j=0;j<ni;j++){
936  index = ci[j];
937  point = &psc[index*3];
938  vecscale3f(wdisp,&pdp[j*3],weight);
939  vecadd3f(point,point,wdisp);
940  }
941  }
942  if(1){
943  //force HAnimSegment.children[] shape nodes using segment->coord to recompile
944  Stack *parents;
945  int k;
946  node->coord->_change++;
947  parents = node->coord->_parentVector;
948  for(k=0;k<vectorSize(parents);k++){
949  struct X3D_Node *parent = vector_get(struct X3D_Node*,parents,k);
950  parent->_change++;
951  }
952  }
953 
954  if(0){
955  //find a few coordinates in segment->coord I hacked, by xyz, and give me their index,
956  // for making a displacer
957  float myfind[9] = {-0.029100f, 1.603000f, 0.042740f, -0.045570f, 1.601000f, 0.036520f, -0.018560f, 1.600000f, 0.043490f };
958  int j,found = FALSE;
959  printf("\n");
960  for(i=0;i<nsc;i++){
961  for(j=0;j<3;j++)
962  if(vecsametol3f(&psc[i*3],&myfind[j*3],.0001f)){
963  printf("%d %f %f %f\n",i,myfind[j*3 + 0],myfind[j*3 +1],myfind[j*3 +2]);
964  found = TRUE;
965  }
966  }
967  if(found)
968  printf("\n");
969  }
970  }
971  normalChildren(node->children);
972  if(node->coord && node->displacers.n){
973  int nsc;
974  float *psc;
975  struct X3D_Coordinate *nc = (struct X3D_Coordinate*)node->coord;
976  psc = (float*)nc->point.p;
977  nsc = nc->point.n;
978  memcpy(psc,node->_origCoords,3*nsc*sizeof(float));
979  }
980 }
981 
982 
983 void child_HAnimSite(struct X3D_HAnimSite *node) {
984 
985  //CHILDREN_COUNT
986  //LOCAL_LIGHT_SAVE
987  //RETURN_FROM_CHILD_IF_NOT_FOR_ME
988 
989  /* do we have to sort this node? */
990 
991  /* do we have a local light for a child? */
992  //LOCAL_LIGHT_CHILDREN(node->children);
993  prep_sibAffectors((struct X3D_Node*)node,&node->__sibAffectors);
994 
995  /* now, just render the non-directionalLight children */
996  normalChildren(node->children);
997 
998  //LOCAL_LIGHT_OFF
999  fin_sibAffectors((struct X3D_Node*)node,&node->__sibAffectors);
1000 
1001 
1002 }
1003 
Definition: Vector.h:36