34 #include <libFreeWRL.h>
37 #include "../vrml_parser/Structs.h"
38 #include "../input/InputFunctions.h"
39 #include "../opengl/LoadTextures.h"
42 #include "../main/headers.h"
43 #include "../opengl/OpenGL_Utils.h"
44 #include "../scenegraph/RenderFuncs.h"
46 #include "../x3d_parser/Bindable.h"
47 #include "../scenegraph/LinearAlgebra.h"
48 #include "../scenegraph/Collision.h"
49 #include "../scenegraph/quaternion.h"
50 #include "../scenegraph/sounds.h"
51 #include "../vrml_parser/CRoutes.h"
52 #include "../opengl/OpenGL_Utils.h"
53 #include "../opengl/Textures.h"
55 #include "../input/SensInterps.h"
61 #define NNC(A) NNC0(X3D_NODE(A)) //node needs compiling
62 #define MNC(A) MNC0(X3D_NODE(A)) //mark node compiled
69 void do_EaseInEaseOut(
void *node){
77 float fraction, u, eout, ein, S;
86 fraction = min(px->set_fraction,px->key.p[kin-1]);
87 fraction = max(px->set_fraction,px->key.p[0]);
89 ispan =find_key(kin,fraction,px->key.p);
90 u = (fraction - px->key.p[ispan-1]) / (px->key.p[ispan] - px->key.p[ispan-1]);
91 eout = px->easeInEaseOut.p[ispan].c[1];
92 ein = px->easeInEaseOut.p[ispan+1].c[0];
96 px->modifiedFraction_changed = u;
103 t = 1.0f / (2.0f - eout - ein);
105 px->modifiedFraction_changed = (t/eout) * u*u;
106 }
else if(u < 1.0f - ein){
107 px->modifiedFraction_changed = (t*(2*u - eout));
109 px->modifiedFraction_changed = 1.0f - (t*(1.0f - u)*(1.0f - u))/ein;
137 static void spline_interp(
int dim,
float *result,
float s,
float *val0,
float *val1,
float *T00,
float *T11){
141 float S[4], *C[4], SH[4];
143 static float H[16] = {
144 2.0f, -3.0f, 0.0f, 1.0f,
145 -2.0f, 3.0f, 0.0f, 0.0f,
146 1.0f, -2.0f, 1.0f, 0.0f,
147 1.0f, -1.0f, 0.0f, 0.0f};
154 vecmultmat4f(SH,S,H);
164 result[i] += SH[j]*C[j][i];
170 static void compute_spline_velocity_Ti(
int dim,
int normalize,
int nval,
float *val,
int nvel,
float* vel,
float *Ti ){
172 if(nvel && vel && nvel == nval){
177 memcpy(Ti,vel,dim*nval*
sizeof(
float));
185 for(i=0;i<nval-1;i++){
189 Di += (val[i+1] - val[i])*(val[i+1] - val[i]);
191 Dtot += (float)sqrt(Di);
197 veli = veli + (vel[i*dim + j]*vel[i*dim + j]);
198 veli = (float)sqrt(veli);
201 Ti[i*dim + j] = Dtot * vel[i*dim + j] / veli;
203 Ti[i*dim + j] = 0.0f;
214 Ti[ 0*dim + j] = vel[0*dim + j];
215 Ti[(nval-1)*dim + j] = vel[1*dim + j];
221 Ti[ 0*dim + j] = 0.0f;
222 Ti[(nval-1)*dim + j] = 0.0f;
226 for(i=1;i<nval-1;i++){
229 Ti[i*dim + j] = (val[(i+1)*dim +j] - val[(i-1)*dim +j]) * .5f;
234 static int iwrap(
int i,
int istart,
int iend){
241 if(iret < istart) iret = iend - (istart - iret);
242 if(iret >= iend ) iret = istart + (iret - iend);
245 static void spline_velocity_adjust_for_keyspan(
int dim,
int closed,
int nval,
float *
key,
float *Ti,
float* T0,
float *T1){
248 int istart, iend, jend,i,j;
260 T1[0*dim +j] = T0[0*dim +j] = Ti[0*dim +j];
261 T1[l*dim +j] = T0[l*dim +j] = Ti[l*dim +j];
264 for(i=istart;i<iend;i++){
266 ip = iwrap(i+1,0,jend);
267 im = iwrap(i-1,0,jend);
268 Fm = 2.0f*(key[ip] - key[i])/(key[ip]-key[im]);
269 Fp = 2.0f*(key[i] - key[im])/(key[ip]-key[im]);
271 T0[i*dim +j] = Fp*Ti[i*dim +j];
272 T1[i*dim +j] = Fm*Ti[i*dim +j];
277 static float span_fraction(
float t,
float t0,
float t1){
279 ret = (t - t0) /(t1 - t0);
283 void do_SplinePositionInterpolator(
void *node){
288 float fraction, sfraction;
298 Ti = MALLOC(
float*,n*dim*
sizeof(
float));
299 compute_spline_velocity_Ti(dim,px->normalizeVelocity,n,(
float*)px->keyValue.p,
300 px->keyVelocity.n,(
float*)px->keyVelocity.p,Ti);
301 T0 = MALLOC(
float*,n*dim*
sizeof(
float));
302 T1 = MALLOC(
float*,n*dim*
sizeof(
float));
304 isclosed = px->closed && vecsame3f(px->keyValue.p[0].c,px->keyValue.p[n-1].c);
305 spline_velocity_adjust_for_keyspan(dim,isclosed,n,px->key.p,Ti,T0,T1);
306 FREE_IF_NZ(px->_T0.p);
307 FREE_IF_NZ(px->_T1.p);
308 px->_T0.p = (
struct SFVec3f*)T0;
310 px->_T1.p = (
struct SFVec3f*)T1;
320 kvin = px->keyValue.n;
325 if ((kvin == 0) || (kin == 0)) {
326 vecset3f(px->value_changed.c,0.0f,0.0f,0.0f);
329 if (kin>kvin) kin=kvin;
332 printf (
"ScalarInterpolator, kin %d kvin %d, vc %f\n",kin,kvin,px->value_changed);
336 fraction = min(px->set_fraction,px->key.p[kin-1]);
337 fraction = max(px->set_fraction,px->key.p[0]);
339 ispan =find_key(kin,fraction,px->key.p) -1;
348 sfraction = span_fraction(fraction,px->key.p[ispan],px->key.p[ispan+1]);
349 spline_interp(dim, px->value_changed.c, sfraction,
350 px->keyValue.p[ispan].c, px->keyValue.p[ispan+1].c,
351 px->_T0.p[ispan].c, px->_T1.p[ispan+1].c);
354 void do_SplinePositionInterpolator2D(
void *node){
358 float fraction,sfraction;
368 Ti = MALLOC(
float*,n*dim*
sizeof(
float));
369 compute_spline_velocity_Ti(dim,px->normalizeVelocity,n,(
float*)px->keyValue.p,
370 px->keyVelocity.n,(
float*)px->keyVelocity.p,Ti);
371 T0 = MALLOC(
float*,n*dim*
sizeof(
float));
372 T1 = MALLOC(
float*,n*dim*
sizeof(
float));
374 isclosed = px->closed && vecsame2f(px->keyValue.p[0].c,px->keyValue.p[n-1].c);
375 spline_velocity_adjust_for_keyspan(dim,isclosed,n,px->key.p,Ti,T0,T1);
376 FREE_IF_NZ(px->_T0.p);
377 FREE_IF_NZ(px->_T1.p);
378 px->_T0.p = (
struct SFVec2f*)T0;
380 px->_T1.p = (
struct SFVec2f*)T1;
390 kvin = px->keyValue.n;
395 if ((kvin == 0) || (kin == 0)) {
396 vecset2f(px->value_changed.c,0.0f,0.0f);
399 if (kin>kvin) kin=kvin;
402 printf (
"ScalarInterpolator, kin %d kvin %d, vc %f\n",kin,kvin,px->value_changed);
406 fraction = min(px->set_fraction,px->key.p[kin-1]);
407 fraction = max(px->set_fraction,px->key.p[0]);
409 ispan =find_key(kin,fraction,px->key.p) -1;
418 sfraction = span_fraction(fraction,px->key.p[ispan],px->key.p[ispan+1]);
419 spline_interp(dim, px->value_changed.c, sfraction,
420 px->keyValue.p[ispan].c, px->keyValue.p[ispan+1].c,
421 px->_T0.p[ispan].c, px->_T1.p[ispan+1].c);
425 void do_SplineScalarInterpolator(
void *node){
431 float fraction, sfraction;
442 Ti = MALLOC(
float*,n*dim*
sizeof(
float));
443 compute_spline_velocity_Ti(dim,px->normalizeVelocity,n,(
float*)px->keyValue.p,
444 px->keyVelocity.n,(
float*)px->keyVelocity.p,Ti);
445 printf(
"\nvelocities\n");
449 T0 = MALLOC(
float*,n*dim*
sizeof(
float));
450 T1 = MALLOC(
float*,n*dim*
sizeof(
float));
452 isclosed = px->closed && px->keyValue.p[0] == px->keyValue.p[n-1];
453 spline_velocity_adjust_for_keyspan(1,isclosed,n,px->key.p,Ti,T0,T1);
457 FREE_IF_NZ(px->_T0.p);
458 FREE_IF_NZ(px->_T1.p);
471 kvin = px->keyValue.n;
476 if ((kvin == 0) || (kin == 0)) {
477 px->value_changed = 0.0;
480 if (kin>kvin) kin=kvin;
483 printf (
"ScalarInterpolator, kin %d kvin %d, vc %f\n",kin,kvin,px->value_changed);
487 fraction = min(px->set_fraction,px->key.p[kin-1]);
488 fraction = max(px->set_fraction,px->key.p[0]);
490 ispan =find_key(kin,fraction,px->key.p) -1;
499 sfraction = span_fraction(fraction,px->key.p[ispan],px->key.p[ispan+1]);
500 spline_interp(dim, (
float*)&px->value_changed, sfraction,
501 &px->keyValue.p[ispan], &px->keyValue.p[ispan+1],
502 &px->_T0.p[ispan], &px->_T1.p[ispan+1]);
509 static double *quaternion2double(
double *xyzw,
const Quaternion *q){
526 double xyzw1[4],xyzw2[4],xyzw[4];
527 quaternion2double(xyzw1,q1);
528 quaternion2double(xyzw2,q2);
529 vecaddd(xyzw,xyzw1,xyzw2);
530 xyzw[3] = xyzw1[3] + xyzw2[3];
531 double2quaternion(ret,xyzw);
535 double xyzw1[4],xyzw2[4],xyzw[4];
536 quaternion2double(xyzw1,q1);
537 quaternion2double(xyzw2,q2);
538 vecdifd(xyzw,xyzw1,xyzw2);
539 xyzw[3] = xyzw1[3] - xyzw2[3];
540 double2quaternion(ret,xyzw);
542 static double fwclampd(
const double val,
const double low,
const double hi){
549 double xyzw1[4], xyzw2[4], dot;
551 quaternion2double(xyzw1,q1);
552 quaternion2double(xyzw2,q1);
555 dot += xyzw1[i]*xyzw2[i];
561 quaternion2double(xyzw,q);
564 double2quaternion(q,xyzw);
567 double angle, angle_over_sine, xyzw[4];
569 quaternion2double(xyzw,q);
570 angle = acos( fwclampd(xyzw[3],-1.0,1.0));
571 angle_over_sine = 0.0;
572 if(angle != 0.0) angle_over_sine = angle/sin(angle);
573 vecscaled(xyzw,xyzw,angle_over_sine);
575 double2quaternion(ret,xyzw);
578 double angle, xyzw[4], sine_over_angle;
580 quaternion2double(xyzw,q);
581 angle = veclengthd(xyzw);
582 sine_over_angle = 0.0;
583 if(angle != 0.0) sine_over_angle = sin(angle) / angle;
584 vecscaled(xyzw,xyzw,sine_over_angle);
585 xyzw[3] = cos(angle);
586 double2quaternion(ret,xyzw);
601 Quaternion qiinv, qiinv_qip1, qiinv_qim1,qadded,qexp;
604 quaternion_inverse(&qiinv,qi);
605 quaternion_multiply(&qiinv_qip1,&qiinv,qip1);
607 quaternion_log(&qiinv_qip1,&qiinv_qip1);
608 quaternion_multiply(&qiinv_qim1,&qiinv,qim1);
609 quaternion_log(&qiinv_qim1,&qiinv_qim1);
611 quaternion_addition(&qadded,&qiinv_qip1,&qiinv_qim1);
612 quaternion2double(xyzw,&qadded);
613 vecscaled(xyzw,xyzw,-.25);
617 double2quaternion(&qexp,xyzw);
618 quaternion_exp(&qexp,&qexp);
621 quaternion_multiply(si,qi,&qexp);
631 int ip1, ip2, im1, kin, iend,i;
633 static int once_debug = 0;
634 if(once_debug != 0)
return;
641 if(vecsame4f(px->keyValue.p[0].c,px->keyValue.p[kin-1].c)) iend = kin -1;
648 if(1) printf(
"%d ri [%f %f %f, %f]\n",i,kVs[i].c[0], kVs[i].c[1], kVs[i].c[2], kVs[i].c[3]);
649 axislength = veclength3f(kVs[i].c);
650 if(axislength != 0.0f)
651 vecscale3f(kVs[i].c,kVs[i].c,1.0f/axislength);
652 if(1) printf(
"%d ri [%f %f %f, %f]\n",i,kVs[i].c[0], kVs[i].c[1], kVs[i].c[2], kVs[i].c[3]);
654 vrmlrot_to_quaternion (&qi, kVs[i].c[0], kVs[i].c[1], kVs[i].c[2], kVs[i].c[3]);
656 ip1 = px->closed ? iwrap(ip1,0,iend) : min(max(ip1,0),kin-2);
657 vrmlrot_to_quaternion (&qip1, kVs[ip1].c[0],kVs[ip1].c[1], kVs[ip1].c[2], kVs[ip1].c[3]);
660 ip2 = px->closed ? iwrap(ip2,0,iend) : min(max(ip2,0),kin-1);
661 vrmlrot_to_quaternion (&qip2, kVs[ip2].c[0],kVs[ip2].c[1], kVs[ip2].c[2], kVs[ip2].c[3]);
664 im1 = px->closed ? iwrap(im1,0,iend) : min(max(im1,0),kin-3);
665 vrmlrot_to_quaternion (&qim1, kVs[im1].c[0],kVs[im1].c[1], kVs[im1].c[2], kVs[im1].c[3]);
667 compute_si(&si,&qi, &qip1, &qim1);
669 compute_si(&sip1,&qip1,&qip2,&qi);
670 printf(
"%d qi [%lf, %lf %lf %lf]\n",i,qi.w,qi.x,qi.y,qi.z);
671 printf(
"%d qi+1 [%lf, %lf %lf %lf]\n",i,qip1.w,qip1.x,qip1.y,qip1.z);
672 printf(
"%d si [%lf, %lf %lf %lf]\n",i,si.w,si.x,si.y,si.z);
673 printf(
"%d si+1 [%lf, %lf %lf %lf]\n",i,sip1.w,sip1.x,sip1.y,sip1.z);
676 quaternion_to_vrmlrot(&si,&xyza[0],&xyza[1],&xyza[2],&xyza[3] );
689 quaternion_scalar_multiply(&t2,t);
690 quaternion_scalar_multiply(&t1,1.0 -t);
691 quaternion_addition(ret,&t1,&t2);
697 dn1 = quaternion_norm(q1);
698 dn2 = quaternion_norm(q2);
699 dot = quaternion_dot(q1,q2);
700 if(dn1 != 0.0 && dn2 != 0.0) dot = dot /(dn1*dn2);
704 quaternion_negate(&r);
706 if(1.0 - dot < .001){
707 quaternion_lerp(ret,q1,&r,t);
710 double angle = acos(dot);
713 quaternion_scalar_multiply(&t1,sin((1.0-t)*angle));
714 quaternion_scalar_multiply(&t2,sin(t*angle));
715 quaternion_addition(ret,&t1,&t2);
717 quaternion_scalar_multiply(ret,1.0/sin(angle));
735 quaternion_addition(&qp,&q0,&q1);
736 quaternion_subtraction(&qm,&q0,&q1);
737 if( quaternion_norm(&qp) < quaternion_norm(&qm) ) quaternion_negate(&q0);
738 quaternion_addition(&qp,&q1,&q2);
739 quaternion_subtraction(&qm,&q1,&q2);
740 if( quaternion_norm(&qp) < quaternion_norm(&qm) ) quaternion_negate(&q2);
741 quaternion_addition(&qp,&q2,&q3);
742 quaternion_subtraction(&qm,&q2,&q3);
743 if( quaternion_norm(&qp) < quaternion_norm(&qm) ) quaternion_negate(&q3);
745 compute_si(s1,&q1,&q2,&q0);
746 compute_si(s2,&q2,&q3,&q1);
752 quaternion_slerp2(&qs,q1,q2,t);
753 quaternion_slerp2(&ss,s1,s2,t);
754 quaternion_slerp2(
final, &qs, &ss, 2.0*t*(1.0 -t));
755 quaternion_normalize(
final);
761 quaternion_inverse(&q1inv,q1);
762 quaternion_multiply(qdiff,q2,&q1inv);
764 quaternion_negate(&q1inv);
765 quaternion_multiply(qdiff,q2,&q1inv);
769 static void squad_compute_velocity_normalized_key_keyvalue(
int closed,
770 int n,
float *keys,
float *values,
771 int *nnorm,
float **normkeys,
float **normvals)
792 double totalangle, angle, velocity;
793 int i,j,k, iend, nspan;
794 float *mkeys,*cumangle, *spanangle, *nkey, *nvals, cumkey;
797 mkeys = MALLOC(
float*,n*100*
sizeof(
float));
799 cumangle = MALLOC(
float*,n*100*
sizeof(
float));
800 spanangle = MALLOC(
float*,n*
sizeof(
float));
804 if(vecsame4f(kVs[0].c,kVs[n-1].c)) iend = n -1;
808 printf(
"key vals before:\n");
810 printf(
"%d %f %f %f %f %f\n",i,keys[i],values[i*4 +0],values[i*4 +1],values[i*4 +2],values[i*4 +3]);
813 for(i=0;i<nspan;i++){
819 vrmlrot_to_quaternion (&qi, kVs[i].c[0], kVs[i].c[1], kVs[i].c[2], kVs[i].c[3]);
820 quaternion_normalize(&qi);
822 ip1 = closed ? iwrap(ip1,0,iend) : min(max(ip1,0),n-2);
823 vrmlrot_to_quaternion (&qip1, kVs[ip1].c[0],kVs[ip1].c[1], kVs[ip1].c[2], kVs[ip1].c[3]);
824 quaternion_normalize(&qip1);
826 ip2 = closed ? iwrap(ip2,0,iend) : min(max(ip2,0),n-1);
827 vrmlrot_to_quaternion (&qip2, kVs[ip2].c[0],kVs[ip2].c[1], kVs[ip2].c[2], kVs[ip2].c[3]);
828 quaternion_normalize(&qip2);
830 im1 = closed ? iwrap(im1,0,iend) : min(max(im1,0),n-3);
831 vrmlrot_to_quaternion (&qim1, kVs[im1].c[0],kVs[im1].c[1], kVs[im1].c[2], kVs[im1].c[3]);
832 quaternion_normalize(&qim1);
837 quaternion_squad_prepare(&qim1,&qi,&qip1,&qip2,&si,&sip1,&qc);
841 float sfraction = j*.1f;
843 h = (double) sfraction;
845 quaternion_squad(&qfinal,&qi,&qc,&si,&sip1,h);
846 quaternion_normalize(&qfinal);
847 quaternion_diff(&qdiff,&qfinal,&qlast);
848 quaternion_normalize(&qdiff);
849 angle = acos(fwclampd(qdiff.w,-1.0,1.0))*2.0;
850 spanangle[i] += (float)angle;
851 mkeys[k] = keys[i] + sfraction * (keys[i+1] - keys[i]);
854 cumangle[k] = (float)totalangle;
855 if(0) printf(
"i %d j %d angle %lf\n",i,j,angle);
860 if(1) printf(
"total angle=%lf\n",totalangle);
861 velocity = totalangle / (keys[n-1] - keys[0]);
864 nkey = *normkeys = MALLOC(
float*, n*
sizeof(
float));
865 nvals = *normvals = MALLOC(
float*,n*
sizeof(
struct SFRotation));
866 memcpy(*normkeys,keys,n*
sizeof(
float));
867 memcpy(*normvals,values,n*
sizeof(
struct SFRotation));
869 cumkey = nkey[0] = keys[0];
870 for(i=0;i<nspan;i++){
871 float newspanfraction = (float)(spanangle[i]/velocity);
872 nkey[i+1] = newspanfraction + cumkey;
873 cumkey += newspanfraction;
877 printf(
"key vals after:\n");
878 for(i=0;i<*nnorm;i++){
879 printf(
"%d %f %f %f %f %f\n",i,nkey[i],nvals[i*4 +0],nvals[i*4 +1],nvals[i*4 +2],nvals[i*4 +3]);
885 void do_SquadOrientationInterpolator(
void *node){
931 kvin = ((px->keyValue).n);
932 kVs = ((px->keyValue).p);
934 if(px->normalizeVelocity){
936 float *normkeys, *normvals;
938 squad_compute_velocity_normalized_key_keyvalue(px->closed,kin,keys,(
float*)kVs,&nnorm,&normkeys,&normvals);
939 px->_normkey.n = nnorm;
940 px->_normkey.p = normkeys;
941 px->_normkeyValue.p = (
struct SFRotation*)normvals;
942 px->_normkeyValue.n = nnorm;
944 kin = px->_normkey.n;
946 keys = px->_normkey.p;
947 kVs = px->_normkeyValue.p;
951 printf (
"starting do_Oint4; keyValue count %d and key count %d\n",
954 if(0) debug_SquadOrientationInterpolator(px);
959 if ((kvin == 0) || (kin == 0)) {
960 px->value_changed.c[0] = (float) 0.0;
961 px->value_changed.c[1] = (float) 0.0;
962 px->value_changed.c[2] = (float) 0.0;
963 px->value_changed.c[3] = (float) 0.0;
966 if (kin>kvin) kin=kvin;
970 if(vecsame4f(kVs[0].c,kVs[kin-1].c)) iend = kin -1;
974 if (px->set_fraction <= keys[0]) {
975 memcpy ((
void *)&px->value_changed,
977 }
else if (px->set_fraction >= keys[kin-1]) {
978 memcpy ((
void *)&px->value_changed,
979 (
void *)&kVs[kvin-1], sizeof (
struct SFRotation));
986 int ip1, ip2, im1, i;
988 ispan = find_key(kin,(
float)(px->set_fraction),keys) -1;
991 sfraction = span_fraction(px->set_fraction,keys[ispan],keys[ispan+1]);
997 printf (
"counter %d interval %f\n",counter,interval);
998 printf (
"angles %f %f %f %f, %f %f %f %f\n",
1000 kVs[counter-1].c[1],
1001 kVs[counter-1].c[2],
1002 kVs[counter-1].c[3],
1013 vrmlrot_to_quaternion (&qi, kVs[i].c[0], kVs[i].c[1], kVs[i].c[2], kVs[i].c[3]);
1014 quaternion_normalize(&qi);
1016 ip1 = px->closed ? iwrap(ip1,0,iend) : min(max(ip1,0),kin-2);
1017 vrmlrot_to_quaternion (&qip1, kVs[ip1].c[0],kVs[ip1].c[1], kVs[ip1].c[2], kVs[ip1].c[3]);
1018 quaternion_normalize(&qip1);
1020 ip2 = px->closed ? iwrap(ip2,0,iend) : min(max(ip2,0),kin-1);
1021 vrmlrot_to_quaternion (&qip2, kVs[ip2].c[0],kVs[ip2].c[1], kVs[ip2].c[2], kVs[ip2].c[3]);
1022 quaternion_normalize(&qip2);
1024 im1 = px->closed ? iwrap(im1,0,iend) : min(max(im1,0),kin-3);
1025 vrmlrot_to_quaternion (&qim1, kVs[im1].c[0],kVs[im1].c[1], kVs[im1].c[2], kVs[im1].c[3]);
1026 quaternion_normalize(&qim1);
1032 h = (double) sfraction;
1035 quaternion_squad_prepare(&qim1,&qi,&qip1,&qip2,&si,&sip1,&qc);
1036 quaternion_squad(&qfinal,&qi,&qc,&si,&sip1,h);
1037 quaternion_normalize(&qfinal);
1038 quaternion_to_vrmlrot(&qfinal,&x, &y, &z, &a);
1039 px->value_changed.c[0] = (float) x;
1040 px->value_changed.c[1] = (float) y;
1041 px->value_changed.c[2] = (float) z;
1042 px->value_changed.c[3] = (float) a;
1045 printf (
"Oint, new angle %f %f %f %f\n",px->value_changed.c[0],
1046 px->value_changed.c[1],px->value_changed.c[2], px->value_changed.c[3]);