FreeWRL / FreeX3D 4.3.0
Component_HAnim.c
1/*
2
3
4X3D 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/*
50HAnim examples:
51http://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
57HAnim Prototypes:
58http://www.web3d.org/x3d/content/examples/Basic/HumanoidAnimation/_pages/page11.html
59HAnim examples:
60http://www.web3d.org/x3d/content/examples/Basic/#HumanoidAnimation
61Specs:
62http://www.web3d.org/documents/specifications/19775-1/V3.3/Part01/components/hanim.html
63These specs don't articulate the field meanings, instead point to an ISO doc:
64http://www.iso.org/iso/home/store/catalogue_tc/catalogue_detail.htm?csnumber=33912
65I19774 about $80
66Here's some free online docs:
67http://www.h-anim.org/
68http://h-anim.org/Specifications/H-Anim200x/ISO_IEC_FCD_19774/
69http://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,
75All the fields are discussed.
76
77July 2016
78- where we left off years ago?
79- define HANIMHANIM below to compile - lots of errors
80Nov 2016
81- stack errors fixed by removing return; at top of some functions
82x but doesn't render/animate correctly: whole body frozen, various limbs moving independently/dismembered
83
84Related Links on HAnim
85http://www.web3d.org/working-groups/humanoid-animation-h-anim
86- The tutorial
87Links on character animation for real-time graphics:
88http://www.cescg.org/CESCG-2002/MPutzKHufnagl/paper.pdf
89- Character Animation for Real-time Applications
90http://apc.dcti.iscte.pt/praticas/Real-Time%20Character%20Animation%20for%20Computer%20Games.pdf
91- (Anderson) Real-Time Character Animation for Computer Games
92https://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
105http://www.nvidia.com/object/doc_characters.html
106- Nvidia link page for various game programming algos with gpu acceleration
107http://ruh.li/AnimationVertexSkinning.html
108- Skinning shader
109http://http.developer.nvidia.com/GPUGems/gpugems_ch04.html
110- Bind pose, dawn
111http://www.3dgep.com/gpu-skinning-of-md5-models-in-opengl-and-cg/
112- Glsl impl of skinning
113http://tech-artists.org/wiki/Vertex_Skinning
114- ogre sample shader
115https://www.cs.tcd.ie/publications/tech-reports/reports.06/TCD-CS-2006-46.pdf
116- dual quat skinning
117
118
119Q if the skeleton isnt rendered, when would you traverse the skeleton
120And whats the output?
121Q isnt there some kind of ik solver that could/should be exposed to sai as a node?
122Otherwise you will need compiled/fast scrpt engine if its all in js, and
123scene authors will need to know all that stuff.
124https://en.wikipedia.org/wiki/Inverse_kinematics
125https://en.wikipedia.org/wiki/Moment_of_inertia
126dug9 july 2016: What's Weird about HAnim:
127a) 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
129b) 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
132dug9 aug 2016: would this work:
133Just 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
137Design Options:
1381. 2-step
139a) 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
143b) 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
1462. Combined step
147a) traverse down segments pushing and multiplying pose
148b) 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
1513. Best Guess
152a) traverse skeleton joints rendering attached solid geometry, and updating influenced skin vertices
153b) divide skin vertices by number of influencers
154c) render skin
155
156Requirements:
157- single deformable mesh should be 'easy' / possible / efficient to update / interpolate
158
159How to update single deformable mesh?
160Please research, as its a common thing in game programming.
161Guesses:
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
171Nov 2016
172state Nov 3, 2016:
173NancyDiving.x3d (scene :HanimHumanoid(HH) with
174 HH->Skeleton children[ RootJoint, Joints, Segments] and
175 HH->joints, HH->segments
176 no HH->skin,->viewpoints
177x I don't see a single skin mesh/vertices being updated by weighted transforms
178x I don't see any mention of Displacer node type
179H: its a LOA 0 (or lowest level, with separate segments for each limb)
180
181freewrl
182x I don't see a single skin mesh vertices being updated by weighted transforms in code below
183x I don't see any mention of Displacer node type below, although its in perl/structs.h
184H:
185it was put together quickly using boilerplate scenegraph calls, for LOA 0,
186but without detailed custom code or testing to make it work for LOA 1+
187
188freewrl rendering of NancyDiving.x3d
189x skin frozen, while indvidual body segments are transformed separately / dismembered,
190x seem to be missing rotations on the segments
191FIXED for LOA-0 ie NancyDiving.x3d
192
193Nov 5, 2016
194Need to add .skin weighted vertex blending for LOA-1 ie BoxMan.x3d
1952 methods:
196CPU - 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
200GPU - 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
204How it would all work
205on 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;
243typedef struct pComponent_HAnim{
244 struct X3D_HAnimHumanoid *HH;
245 double HHMatrix[16];
246
248void *Component_HAnim_constructor(){
249 void *v = MALLOCV(sizeof(struct pComponent_HAnim));
250 memset(v,0,sizeof(struct pComponent_HAnim));
251 return v;
252}
253void 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}
263void 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
273void 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}
294void 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
354void 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
384void 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}
405void 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
465void 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
495typedef struct {
496 double mat [16];
497 float normat[9];
498} JMATRIX;
499enum {
500 VERTEXTRANSFORMMETHOD_CPU = 1,
501 VERTEXTRANSFORMMETHOD_GPU = 2,
502};
503static int vertexTransformMethod = VERTEXTRANSFORMMETHOD_CPU;
504void render_HAnimHumanoid (struct X3D_HAnimHumanoid *node) {
505 /* save the skinCoords and skinNormals for use in following HAnimJoints */
506 /* printf ("rendering HAnimHumanoid\n"); */
507}
508
509void 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}
603int 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}
609void compile_HAnimHumanoid(struct X3D_HAnimHumanoid *node){
610 //printf("compile_HAnimHumanoid\n");
611 //check if the coordinate count is the same
612 INITIALIZE_EXTENT
613
614 int nsc = 0, nsn = 0;
615 float *psc = NULL, *psn = NULL;
616 if(node->skinCoord && node->skinCoord->_nodeType == NODE_Coordinate){
617 float ee[6];
618 struct X3D_Coordinate * nc = (struct X3D_Coordinate * )node->skinCoord;
619 nsc = nc->point.n;
620 psc = (float*)nc->point.p;
621 node->_origCoords = realloc(node->_origCoords,nsc*3*sizeof(float));
622 memcpy(node->_origCoords,psc,nsc*3*sizeof(float));
623 if(0){
624 //find a few coordinates in skinCoord I hacked, by xyz, and give me their index, for making a displacer
625 float myfind[9] = {-0.030000f, -0.070000f, 1.777000f, -0.070000f, 1.777000f, 0.130000f, 1.777000f, 0.130000f, 0.070000f };
626 int i,j;
627 for(i=0;i<nsc;i++){
628 for(j=0;j<3;j++)
629 if(vecsametol3f(&psc[i*3],&myfind[j*3],.001f)){
630 printf("%d %f %f %f\n",i,myfind[j*3 + 0],myfind[j*3 +1],myfind[j*3 +2]);
631 }
632 }
633 }
634 extent6f_from_box3fn(ee,nc->point.p->c, nc->point.n);
635 setExtent(ee[0],ee[1],ee[2],ee[3],ee[4],ee[5],X3D_NODE(node));
636 }
637 if(node->skinNormal && node->skinNormal->_nodeType == NODE_Normal){
638 struct X3D_Normal * nn = (struct X3D_Normal * )node->skinNormal;
639 //Assuming 1 normal per coord, coord 1:1 normal
640 nsn = nn->vector.n;
641 psn = (float*)nn->vector.p;
642 node->_origNorms = realloc(node->_origNorms,nsn*3*sizeof(float));
643 memcpy(node->_origNorms,psn,nsn*3*sizeof(float));
644 }
645
646 //allocate the joint-transform_index and joint-weight arrays
647 //Nov 2016: max 4: meaning each skinCoord can have up to 4 joints referencing/influencing it
648 //4 chosen so it's easier to port to GPU method with vec4
649 if(node->_NV == 0 || node->_NV != nsc){
650 node->_PVI = realloc(node->_PVI,nsc*4*sizeof(float)); //indexes, up to 4 joints per skinCoord
651 node->_PVW = realloc(node->_PVW,nsc*4*sizeof(float)); //weights, up to 4 joints per skinCoord
652 node->_NV = nsc;
653 }
654 //allocate the transform array
655 if(node->_JT == NULL) {
656 if(vertexTransformMethod == VERTEXTRANSFORMMETHOD_GPU){
657 //new stack quat + position
658 }else if(vertexTransformMethod == VERTEXTRANSFORMMETHOD_CPU){
659 node->_JT = newStack(JMATRIX); //we don't know how many joints there are - need to count as we go
660 }
661 }
662 MARK_NODE_COMPILED
663}
664
665void child_HAnimHumanoid(struct X3D_HAnimHumanoid *node) {
666 int nc;
667 //float *originalCoords;
668 Stack *JT;
669 ppComponent_HAnim p = (ppComponent_HAnim)gglobal()->Component_HAnim.prv;
670 COMPILE_IF_REQUIRED
671
672 //LOCAL_LIGHT_SAVE
673
674 /* any segments at all? */
675/*
676printf ("hanimHumanoid, segment counts joints %d segs %d sites %d skeleton %d skin %d vps %d\n",
677 node->joints.n,
678 node->segments.n,
679 node->sites.n,
680 node->skeleton.n,
681 node->skin.n,
682 node->viewpoints.n);
683*/
684
685 nc = node->joints.n + node->segments.n + node->viewpoints.n + node->sites.n +
686 node->skeleton.n + node->skin.n;
687
688 RETURN_FROM_CHILD_IF_NOT_FOR_ME
689
690 if(renderstate()->render_vp){
691 /* Lets do viewpoints */
692 normalChildren(node->viewpoints);
693 return;
694 }
695
696
697 // segments, joints, sites are flat-lists for convenience
698 // skeleton is the scenegraph-like transform hierarchy of joints and segments and sites
699 // skin relies on something updating its vertices based on skeleton transforms
700 /* Lets do segments first */
701 /* now, just render the non-directionalLight segments */
702 if(0) normalChildren(node->segments);
703
704
705 /* Lets do joints second */
706 /* do we have to sort this node? */
707 /* now, just render the non-directionalLight joints */
708 if(0) normalChildren(node->joints);
709
710
711 /* Lets do sites third */
712 /* do we have to sort this node? */
713 /* do we have a local light for a child? */
714 //LOCAL_LIGHT_CHILDREN(node->sites);
715 /* now, just render the non-directionalLight sites */
716 if(0) normalChildren(node->sites);
717
718 prep_sibAffectors((struct X3D_Node*)node,&node->__sibAffectors);
719 /* Lets do skeleton fourth */
720 /* do we have to sort this node? */
721 /* now, just render the non-directionalLight skeleton */
722 //skeleton is the basic thing to render for LOA 0
723 memset(node->_PVI,0,4*node->_NV*sizeof(float));
724 memset(node->_PVW,0,4*node->_NV*sizeof(float));
725 JT = node->_JT;
726 JT->n = 0;
727
728 //in theory, HH, HHMatrix could be a stack, so you could have an hanimhumaoid within an hanimhunaniod
729 p->HH = node;
730 {
731 double modelviewMatrix[16];
732 FW_GL_GETDOUBLEV(GL_MODELVIEW_MATRIX, modelviewMatrix);
733 matinverseAFFINE(p->HHMatrix,modelviewMatrix);
734 }
735 if(node->skin.n){
736 if(vertexTransformMethod == VERTEXTRANSFORMMETHOD_CPU){
737 //save original coordinates before rendering skeleton
738 // - HAnimJoint may have displacers that change the Coords
739 //transform each vertex and its normal using weighted transform
740 int nsc = 0, nsn = 0;
741 float *psc = NULL, *psn = NULL;
742 if(node->skinCoord && node->skinCoord->_nodeType == NODE_Coordinate){
743 struct X3D_Coordinate * nc = (struct X3D_Coordinate * )node->skinCoord;
744 struct X3D_Normal *nn = (struct X3D_Normal *)node->skinNormal; //might be NULL
745 nsc = nc->point.n;
746 psc = (float*)nc->point.p;
747 memcpy(psc,node->_origCoords,3*nsc*sizeof(float));
748 if(nn){
749 nsn = nn->vector.n;
750 psn = (float *)nn->vector.p;
751 memcpy(psn,node->_origNorms,3*nsn*sizeof(float));
752 }
753 }
754 }
755 }
756 if(1) normalChildren(node->skeleton);
757
758 if(node->skin.n){
759 if(vertexTransformMethod == VERTEXTRANSFORMMETHOD_CPU){
760 //save original coordinates
761 //transform each vertex and its normal using weighted transform
762 int i,j,nsc = 0;
763 // int nsn = 0;
764 float *psc = NULL, *psn = NULL;
765 if(node->skinCoord && node->skinCoord->_nodeType == NODE_Coordinate){
766 float ee[6];
767 struct X3D_Coordinate * nc = (struct X3D_Coordinate * )node->skinCoord;
768 struct X3D_Normal *nn = (struct X3D_Normal *)node->skinNormal; //might be NULL
769 nsc = nc->point.n;
770 psc = (float*)nc->point.p[0].c;
771 //memcpy(psc,node->_origCoords,3*nsc*sizeof(float));
772 if(nn){
773 // nsn = nn->vector.n;
774 psn = (float *)nn->vector.p;
775 //memcpy(psn,node->_origNorms,3*nsn*sizeof(float));
776 }
777
778 for(i=0;i<nsc;i++){
779 float totalWeight;
780 float *point, *norm;
781 float newpoint[3], newnorm[3];
782 float *PVW, *PVI;
783
784 point = &psc[i*3];
785 norm = NULL;
786 if(nn) norm = &psn[i*3];
787 PVW = node->_PVW;
788 PVI = node->_PVI;
789
790 memset(newpoint,0,3*sizeof(float));
791 memset(newnorm,0,3*sizeof(float));
792 totalWeight = 0.0f;
793 for(j=0;j<4;j++){
794 int jointTransformIndex = (int)PVI[i*4 + j];
795 float wt = PVW[i*4 + j];
796 if(jointTransformIndex > 0){
797 float tpoint[3], tnorm[3];
798 JMATRIX jointMatrix;
799 jointMatrix = vector_get(JMATRIX,node->_JT,jointTransformIndex -1);
800 transformf(tpoint,point,jointMatrix.mat);
801 vecscale3f(tpoint,tpoint,wt);
802 vecadd3f(newpoint,newpoint,tpoint);
803 if(nn){
804 transform3x3f(tnorm,norm,jointMatrix.normat);
805 vecnormalize3f(tnorm,tnorm);
806 vecscale3f(tnorm,tnorm,wt);
807 vecadd3f(newnorm,newnorm,tnorm);
808 }
809 totalWeight += wt;
810 }
811 }
812 if(totalWeight > 0.0f){
813 vecscale3f(newpoint,newpoint,1.0f/totalWeight);
814 veccopy3f(point,newpoint);
815 if(nn){
816 vecscale3f(newnorm,newnorm,1.0f/totalWeight);
817 vecnormalize3f(norm,newnorm);
818 }
819 }
820 }
821 if(0){
822 //print out before and after coords
823 float *osc = node->_origCoords;
824 for(i=0;i<nsc;i++){
825 printf("%d ",i);
826 for(j=0;j<3;j++) printf("%f ",psc[i*3 +j]);
827 printf("/ ");
828 for(j=0;j<3;j++) printf("%f ",osc[i*3 +j]);
829 printf("\n");
830 }
831 printf("\n");
832 }
833
834 //trigger recompile of skin->shapes when rendering skin
835 //Nov 6, 2016: recompiling a shape / polyrep on each frame eats memory
836 //NODE_NEEDS_COMPILING
837 if(1){
838 int k;
839 Stack *parents;
840 node->skinCoord->_change++;
841 parents = node->skinCoord->_parentVector;
842 for(k=0;k<vectorSize(parents);k++){
843 struct X3D_Node *parent = vector_get(struct X3D_Node*,parents,k);
844 parent->_change++;
845 }
846 }
847
848 }
849 }else if(vertexTransformMethod == VERTEXTRANSFORMMETHOD_GPU){
850 //push shader flaga with += SKELETAL
851 }
852
853 if(1) normalChildren(node->skin);
854 if(vertexTransformMethod == VERTEXTRANSFORMMETHOD_GPU){
855 //pop shader flags
856 } else if(vertexTransformMethod == VERTEXTRANSFORMMETHOD_CPU){
857 //restore original coordinates
858 int nsc, nsn;
859 float *psc, *psn;
860 struct X3D_Coordinate * nc = (struct X3D_Coordinate * )node->skinCoord;
861 struct X3D_Normal * nn = (struct X3D_Normal * )node->skinNormal;
862 nsc = nc->point.n;
863 psc = (float*)nc->point.p;
864 memcpy(psc,node->_origCoords,3*nsc*sizeof(float));
865 if(nn){
866 nsn = nn->vector.n;
867 psn = (float*)nn->vector.p;
868 memcpy(psn,node->_origNorms,3*nsn*sizeof(float));
869 }
870 }
871 } //if skin
872 fin_sibAffectors((struct X3D_Node*)node,&node->__sibAffectors);
873
874
875 /* did we have that directionalLight? */
876 //LOCAL_LIGHT_OFF
877}
878
879
880void child_HAnimJoint(struct X3D_HAnimJoint *node) {
881
882 //CHILDREN_COUNT
883 /* any children at all? */
884 //if (nc==0) return;
885
886 /* should we go down here? */
887 //RETURN_FROM_CHILD_IF_NOT_FOR_ME
888
889 /* do we have to sort this node? */
890
891 /* just render the non-directionalLight children */
892 normalChildren(node->children);
893
894
895}
896float *vecmix3f(float *out3, float* a3, float *b3, float fraction){
897 int i;
898 for(i=0;i<3;i++){
899 out3[i] = (1.0f - fraction)*a3[i] + fraction*b3[i];
900 }
901 return out3;
902}
903void child_HAnimSegment(struct X3D_HAnimSegment *node) {
904
905 //CHILDREN_COUNT
906
907
908//note to implementer: have to POSSIBLE_PROTO_EXPANSION(node->coord, tmpN)
909
910 /* any children at all? */
911 //if (nc==0) return;
912
913 /* should we go down here? */
914 //RETURN_FROM_CHILD_IF_NOT_FOR_ME
915
916 /* do we have to sort this node? Only if not a proto - only first node has visible children. */
917
918 /* now, just render the non-directionalLight children */
919 if(node->coord && node->displacers.n){
920
921 int nsc, ni, i;
922 float *psc, *pdp;
923 int *ci;
924 struct X3D_Coordinate *nc = (struct X3D_Coordinate*)node->coord;
925 psc = (float*)nc->point.p;
926 nsc = nc->point.n;
927 if(!node->_origCoords)
928 node->_origCoords = malloc(3*nsc*sizeof(float));
929 memcpy(node->_origCoords,psc,3*nsc*sizeof(float));
930 for(i=0;i<node->displacers.n;i++){
931 int index, j;
932 float *point, weight, wdisp[3];
933 struct X3D_HAnimDisplacer *dp = (struct X3D_HAnimDisplacer *)node->displacers.p[i];
934
935 weight = dp->weight;
936 //printf(" %f ",weight);
937 pdp = (float*)dp->displacements.p;
938 // ndp = dp->displacements.n;
939
940 ni = dp->coordIndex.n;
941 ci = dp->coordIndex.p;
942 for(j=0;j<ni;j++){
943 index = ci[j];
944 point = &psc[index*3];
945 vecscale3f(wdisp,&pdp[j*3],weight);
946 vecadd3f(point,point,wdisp);
947 }
948 }
949 if(1){
950 //force HAnimSegment.children[] shape nodes using segment->coord to recompile
951 Stack *parents;
952 int k;
953 node->coord->_change++;
954 parents = node->coord->_parentVector;
955 for(k=0;k<vectorSize(parents);k++){
956 struct X3D_Node *parent = vector_get(struct X3D_Node*,parents,k);
957 parent->_change++;
958 }
959 }
960
961 if(0){
962 //find a few coordinates in segment->coord I hacked, by xyz, and give me their index,
963 // for making a displacer
964 float myfind[9] = {-0.029100f, 1.603000f, 0.042740f, -0.045570f, 1.601000f, 0.036520f, -0.018560f, 1.600000f, 0.043490f };
965 int j,found = FALSE;
966 printf("\n");
967 for(i=0;i<nsc;i++){
968 for(j=0;j<3;j++)
969 if(vecsametol3f(&psc[i*3],&myfind[j*3],.0001f)){
970 printf("%d %f %f %f\n",i,myfind[j*3 + 0],myfind[j*3 +1],myfind[j*3 +2]);
971 found = TRUE;
972 }
973 }
974 if(found)
975 printf("\n");
976 }
977 }
978 normalChildren(node->children);
979 if(node->coord && node->displacers.n){
980 int nsc;
981 float *psc;
982 struct X3D_Coordinate *nc = (struct X3D_Coordinate*)node->coord;
983 psc = (float*)nc->point.p;
984 nsc = nc->point.n;
985 memcpy(psc,node->_origCoords,3*nsc*sizeof(float));
986 }
987}
988
989
990void child_HAnimSite(struct X3D_HAnimSite *node) {
991
992 //CHILDREN_COUNT
993 //LOCAL_LIGHT_SAVE
994 //RETURN_FROM_CHILD_IF_NOT_FOR_ME
995
996 /* do we have to sort this node? */
997
998 /* do we have a local light for a child? */
999 //LOCAL_LIGHT_CHILDREN(node->children);
1000 prep_sibAffectors((struct X3D_Node*)node,&node->__sibAffectors);
1001
1002 /* now, just render the non-directionalLight children */
1003 normalChildren(node->children);
1004
1005 //LOCAL_LIGHT_OFF
1006 fin_sibAffectors((struct X3D_Node*)node,&node->__sibAffectors);
1007
1008
1009}
1010