Sorry for the big commit, but I've been fixing many of these
[blender.git] / intern / elbeem / intern / attributes.cpp
1 /******************************************************************************
2  *
3  * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
4  * Copyright 2003,2004 Nils Thuerey
5  *
6  * configuration attribute storage class and attribute class
7  *
8  *****************************************************************************/
9
10 #include "attributes.h"
11 #include "ntl_matrices.h"
12 #include "elbeem.h"
13 #include <sstream>
14
15
16 //! output attribute values? on=1/off=0
17 #define DEBUG_ATTRIBUTES 0
18
19 //! output channel values? on=1/off=0
20 #define DEBUG_CHANNELS 0
21
22
23 /******************************************************************************
24  * attribute conversion functions
25  *****************************************************************************/
26
27 bool Attribute::initChannel(int elemSize) {
28         if(!mIsChannel) return true;
29         if(mChannelInited==elemSize) {
30                 // already inited... ok
31                 return true;
32         } else {
33                 // sanity check
34                 if(mChannelInited>0) {
35                         errMsg("Attribute::initChannel","Duplicate channel init!? ("<<mChannelInited<<" vs "<<elemSize<<")...");
36                         return false;
37                 }
38         }
39         
40         if((mValue.size() % (elemSize+1)) !=  0) {
41                 errMsg("Attribute::initChannel","Invalid # elements in Attribute...");
42                 return false;
43         }
44         
45         int numElems = mValue.size()/(elemSize+1);
46         vector<string> newvalue;
47         for(int i=0; i<numElems; i++) {
48         //errMsg("ATTR"," i"<<i<<" "<<mName); // debug
49
50                 vector<string> elem(elemSize);
51                 for(int j=0; j<elemSize; j++) {
52                 //errMsg("ATTR"," j"<<j<<" "<<mValue[i*(elemSize+1)+j]  ); // debug
53                         elem[j] = mValue[i*(elemSize+1)+j];
54                 }
55                 mChannel.push_back(elem);
56                 // use first value as default
57                 if(i==0) newvalue = elem;
58                 
59                 double t = 0.0; // similar to getAsFloat
60                 const char *str = mValue[i*(elemSize+1)+elemSize].c_str();
61                 char *endptr;
62                 t = strtod(str, &endptr);
63                 if((str!=endptr) && (*endptr != '\0')) return false;
64                 mTimes.push_back(t);
65                 //errMsg("ATTR"," t"<<t<<" "); // debug
66         }
67         for(int i=0; i<numElems-1; i++) {
68                 if(mTimes[i]>mTimes[i+1]) {
69                         errMsg("Attribute::initChannel","Invalid time at entry "<<i<<" setting to "<<mTimes[i]);
70                         mTimes[i+1] = mTimes[i];
71                 }
72         }
73
74         // dont change until done with parsing, and everythings ok
75         mValue = newvalue;
76
77         mChannelInited = elemSize;
78         if(DEBUG_CHANNELS) print();
79         return true;
80 }
81
82 // get value as string 
83 string Attribute::getAsString(bool debug)
84 {
85         if(mIsChannel && (!debug)) {
86                 errMsg("Attribute::getAsString", "Attribute \"" << mName << "\" used as string is a channel! Not allowed...");
87                 print();
88                 return string("");
89         }
90         if(mValue.size()!=1) {
91                 // for directories etc. , this might be valid! cutoff "..." first
92                 string comp = getCompleteString();
93                 if(comp.size()<2) return string("");
94                 return comp.substr(1, comp.size()-2);
95         }
96         return mValue[0];
97 }
98
99 // get value as integer value
100 int Attribute::getAsInt()
101 {
102         bool success = true;
103         int ret = 0;
104
105         if(!initChannel(1)) success=false; 
106         if(success) {
107                 if(mValue.size()!=1) success = false;
108                 else {
109                         const char *str = mValue[0].c_str();
110                         char *endptr;
111                         ret = strtol(str, &endptr, 10);
112                         if( (str==endptr) ||
113                                         ((str!=endptr) && (*endptr != '\0')) )success = false;
114                 }
115         }
116
117         if(!success) {
118                 errMsg("Attribute::getAsInt", "Attribute \"" << mName << "\" used as int has invalid value '"<< getCompleteString() <<"' ");
119                 errMsg("Attribute::getAsInt", "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" );
120                 errMsg("Attribute::getAsInt", "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" );
121 #if ELBEEM_PLUGIN!=1
122                 gElbeemState = -4; // parse error
123 #endif
124                 return 0;
125         }
126         return ret;
127 }
128
129
130 // get value as integer value
131 bool Attribute::getAsBool() 
132 {
133         int val = getAsInt();
134         if(val==0) return false;
135         else                     return true;
136 }
137
138
139 // get value as double value
140 double Attribute::getAsFloat()
141 {
142         bool success = true;
143         double ret = 0.0;
144
145         if(!initChannel(1)) success=false; 
146         if(success) {
147                 if(mValue.size()!=1) success = false;
148                 else {
149                         const char *str = mValue[0].c_str();
150                         char *endptr;
151                         ret = strtod(str, &endptr);
152                         if((str!=endptr) && (*endptr != '\0')) success = false;
153                 }
154         }
155
156         if(!success) {
157                 print();
158                 errMsg("Attribute::getAsFloat", "Attribute \"" << mName << "\" used as double has invalid value '"<< getCompleteString() <<"' ");
159                 errMsg("Attribute::getAsFloat", "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" );
160                 errMsg("Attribute::getAsFloat", "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" );
161 #if ELBEEM_PLUGIN!=1
162                 gElbeemState = -4; // parse error
163 #endif
164                 return 0.0;
165         }
166         return ret;
167 }
168
169 // get value as 3d vector 
170 ntlVec3d Attribute::getAsVec3d()
171 {
172         bool success = true;
173         ntlVec3d ret(0.0);
174
175         if(!initChannel(3)) success=false; 
176         if(success) {
177                 if(mValue.size()==1) {
178                         const char *str = mValue[0].c_str();
179                         char *endptr;
180                         double rval = strtod(str, &endptr);
181                         if( (str==endptr) ||
182                                         ((str!=endptr) && (*endptr != '\0')) )success = false;
183                         if(success) ret = ntlVec3d( rval );
184                 } else if(mValue.size()==3) {
185                         char *endptr;
186                         const char *str = NULL;
187
188                         str = mValue[0].c_str();
189                         double rval1 = strtod(str, &endptr);
190                         if( (str==endptr) ||
191                                         ((str!=endptr) && (*endptr != '\0')) )success = false;
192
193                         str = mValue[1].c_str();
194                         double rval2 = strtod(str, &endptr);
195                         if( (str==endptr) ||
196                                         ((str!=endptr) && (*endptr != '\0')) )success = false;
197
198                         str = mValue[2].c_str();
199                         double rval3 = strtod(str, &endptr);
200                         if( (str==endptr) ||
201                                         ((str!=endptr) && (*endptr != '\0')) )success = false;
202
203                         if(success) ret = ntlVec3d( rval1, rval2, rval3 );
204                 } else {
205                         success = false;
206                 }
207         }
208
209         if(!success) {
210                 errMsg("Attribute::getAsVec3d", "Attribute \"" << mName << "\" used as Vec3d has invalid value '"<< getCompleteString() <<"' ");
211                 errMsg("Attribute::getAsVec3d", "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" );
212                 errMsg("Attribute::getAsVec3d", "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" );
213 #if ELBEEM_PLUGIN!=1
214                 gElbeemState = -4; // parse error
215 #endif
216                 return ntlVec3d(0.0);
217         }
218         return ret;
219 }
220                 
221 // get value as 4x4 matrix 
222 void Attribute::getAsMat4Gfx(ntlMat4Gfx *mat)
223 {
224         bool success = true;
225         ntlMat4Gfx ret(0.0);
226         char *endptr;
227
228         if(mValue.size()==1) {
229                 const char *str = mValue[0].c_str();
230                 double rval = strtod(str, &endptr);
231                 if( (str==endptr) ||
232                                 ((str!=endptr) && (*endptr != '\0')) )success = false;
233                 if(success) {
234                         ret = ntlMat4Gfx( 0.0 );
235                         ret.value[0][0] = rval;
236                         ret.value[1][1] = rval;
237                         ret.value[2][2] = rval;
238                         ret.value[3][3] = 1.0;
239                 }
240         } else if(mValue.size()==9) {
241                 // 3x3
242                 for(int i=0; i<3;i++) {
243                         for(int j=0; j<3;j++) {
244                                 const char *str = mValue[i*3+j].c_str();
245                                 ret.value[i][j] = strtod(str, &endptr);
246                                 if( (str==endptr) ||
247                                                 ((str!=endptr) && (*endptr != '\0')) ) success = false;
248                         }
249                 }
250         } else if(mValue.size()==16) {
251                 // 4x4
252                 for(int i=0; i<4;i++) {
253                         for(int j=0; j<4;j++) {
254                                 const char *str = mValue[i*4+j].c_str();
255                                 ret.value[i][j] = strtod(str, &endptr);
256                                 if( (str==endptr) ||
257                                                 ((str!=endptr) && (*endptr != '\0')) ) success = false;
258                         }
259                 }
260
261         } else {
262                 success = false;
263         }
264
265         if(!success) {
266                 errMsg("Attribute::getAsMat4Gfx", "Attribute \"" << mName << "\" used as Mat4x4 has invalid value '"<< getCompleteString() <<"' ");
267                 errMsg("Attribute::getAsMat4Gfx", "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" );
268                 errMsg("Attribute::getAsMat4Gfx", "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" );
269 #if ELBEEM_PLUGIN!=1
270                 gElbeemState = -4; // parse error
271 #endif
272                 *mat = ntlMat4Gfx(0.0);
273                 return;
274         }
275         *mat = ret;
276 }
277                 
278
279 // get the concatenated string of all value string
280 string Attribute::getCompleteString()
281 {
282         string ret;
283         for(size_t i=0;i<mValue.size();i++) {
284                 ret += mValue[i];
285                 if(i<mValue.size()-1) ret += " ";
286         }
287         return ret;
288 }
289
290
291 /******************************************************************************
292  * channel returns
293  *****************************************************************************/
294
295 //! get channel as double value
296 AnimChannel<double> Attribute::getChannelFloat() {
297         vector<double> timeVec;
298         vector<double> valVec;
299         
300         if((!initChannel(1)) || (!mIsChannel)) {
301                 timeVec.push_back( 0.0 );
302                 valVec.push_back( getAsFloat() );
303         } else {
304         for(size_t i=0; i<mChannel.size(); i++) {
305                 mValue = mChannel[i];
306                 double val = getAsFloat();
307                 timeVec.push_back( mTimes[i] );
308                 valVec.push_back( val );
309         }}
310
311         return AnimChannel<double>(valVec,timeVec);
312 }
313
314 //! get channel as integer value
315 AnimChannel<int> Attribute::getChannelInt() { 
316         vector<double> timeVec;
317         vector<int> valVec;
318         
319         if((!initChannel(1)) || (!mIsChannel)) {
320                 timeVec.push_back( 0.0 );
321                 valVec.push_back( getAsInt() );
322         } else {
323         for(size_t i=0; i<mChannel.size(); i++) {
324                 mValue = mChannel[i];
325                 int val = getAsInt();
326                 timeVec.push_back( mTimes[i] );
327                 valVec.push_back( val );
328         }}
329
330         return AnimChannel<int>(valVec,timeVec);
331 }
332
333 //! get channel as integer value
334 AnimChannel<ntlVec3d> Attribute::getChannelVec3d() { 
335         vector<double> timeVec;
336         vector<ntlVec3d> valVec;
337         
338         if((!initChannel(3)) || (!mIsChannel)) {
339                 timeVec.push_back( 0.0 );
340                 valVec.push_back( getAsVec3d() );
341         } else {
342         for(size_t i=0; i<mChannel.size(); i++) {
343                 mValue = mChannel[i];
344                 ntlVec3d val = getAsVec3d();
345                 timeVec.push_back( mTimes[i] );
346                 valVec.push_back( val );
347         }}
348
349         return AnimChannel<ntlVec3d>(valVec,timeVec);
350 }
351
352
353 /******************************************************************************
354  * check if there were unknown params
355  *****************************************************************************/
356 bool AttributeList::checkUnusedParams()
357 {
358         bool found = false;
359         for(map<string, Attribute*>::iterator i=mAttrs.begin();
360                         i != mAttrs.end(); i++) {
361                 if((*i).second) {
362                         if(!(*i).second->getUsed()) {
363                                 errMsg("AttributeList::checkUnusedParams", "List "<<mName<<" has unknown parameter '"<<(*i).first<<"' = '"<< mAttrs[(*i).first]->getAsString(true) <<"' ");
364                                 found = true;
365                         }
366                 }
367         }
368         return found;
369 }
370 //! set all params to used, for invisible objects
371 void AttributeList::setAllUsed() {
372         for(map<string, Attribute*>::iterator i=mAttrs.begin();
373                         i != mAttrs.end(); i++) {
374                 if((*i).second) {
375                         (*i).second->setUsed(true);
376                 }
377         }
378 }
379
380 /******************************************************************************
381  * Attribute list read functions
382  *****************************************************************************/
383 int AttributeList::readInt(string name, int defaultValue, string source,string target, bool needed) {
384         if(!exists(name)) {
385                 if(needed) { errFatal("AttributeList::readInt","Required attribute '"<<name<<"' for "<< source <<"  not set! ", SIMWORLD_INITERROR); }
386                 return defaultValue;
387         } 
388         if(DEBUG_ATTRIBUTES==1) { debugOut( source << " Var '"<< target <<"' set to '"<< find(name)->getCompleteString() <<"' as type int " , 3); }
389         find(name)->setUsed(true);
390         return find(name)->getAsInt(); 
391 }
392 bool AttributeList::readBool(string name, bool defaultValue, string source,string target, bool needed) {
393         if(!exists(name)) {
394                 if(needed) { errFatal("AttributeList::readBool","Required attribute '"<<name<<"' for "<< source <<"  not set! ", SIMWORLD_INITERROR); }
395                 return defaultValue;
396         } 
397         if(DEBUG_ATTRIBUTES==1) { debugOut( source << " Var '"<< target <<"' set to '"<< find(name)->getCompleteString() <<"' as type int " , 3); }
398         find(name)->setUsed(true);
399         return find(name)->getAsBool(); 
400 }
401 double AttributeList::readFloat(string name, double defaultValue, string source,string target, bool needed) {
402         if(!exists(name)) {
403                 if(needed) { errFatal("AttributeList::readFloat","Required attribute '"<<name<<"' for "<< source <<"  not set! ", SIMWORLD_INITERROR); }
404                 return defaultValue;
405         } 
406         if(DEBUG_ATTRIBUTES==1) { debugOut( source << " Var '"<< target <<"' set to '"<< find(name)->getCompleteString() <<"' as type int " , 3); }
407         find(name)->setUsed(true);
408         return find(name)->getAsFloat(); 
409 }
410 string AttributeList::readString(string name, string defaultValue, string source,string target, bool needed) {
411         if(!exists(name)) {
412                 if(needed) { errFatal("AttributeList::readInt","Required attribute '"<<name<<"' for "<< source <<"  not set! ", SIMWORLD_INITERROR); }
413                 return defaultValue;
414         } 
415         if(DEBUG_ATTRIBUTES==1) { debugOut( source << " Var '"<< target <<"' set to '"<< find(name)->getCompleteString() <<"' as type int " , 3); }
416         find(name)->setUsed(true);
417         return find(name)->getAsString(false); 
418 }
419 ntlVec3d AttributeList::readVec3d(string name, ntlVec3d defaultValue, string source,string target, bool needed) {
420         if(!exists(name)) {
421                 if(needed) { errFatal("AttributeList::readInt","Required attribute '"<<name<<"' for "<< source <<"  not set! ", SIMWORLD_INITERROR); }
422                 return defaultValue;
423         } 
424         if(DEBUG_ATTRIBUTES==1) { debugOut( source << " Var '"<< target <<"' set to '"<< find(name)->getCompleteString() <<"' as type int " , 3); }
425         find(name)->setUsed(true);
426         return find(name)->getAsVec3d(); 
427 }
428
429 void AttributeList::readMat4Gfx(string name, ntlMat4Gfx defaultValue, string source,string target, bool needed, ntlMat4Gfx *mat) {
430         if(!exists(name)) {
431                 if(needed) { errFatal("AttributeList::readInt","Required attribute '"<<name<<"' for "<< source <<"  not set! ", SIMWORLD_INITERROR); }
432                 *mat = defaultValue;
433                 return;
434         } 
435         if(DEBUG_ATTRIBUTES==1) { debugOut( source << " Var '"<< target <<"' set to '"<< find(name)->getCompleteString() <<"' as type int " , 3); }
436         find(name)->setUsed(true);
437         find(name)->getAsMat4Gfx( mat ); 
438         return;
439 }
440
441 // set that a parameter can be given, and will be ignored...
442 bool AttributeList::ignoreParameter(string name, string source) {
443         if(!exists(name)) return false;
444         find(name)->setUsed(true);
445         if(DEBUG_ATTRIBUTES==1) { debugOut( source << " Param '"<< name <<"' set but ignored... " , 3); }
446         return true;
447 }
448                 
449 // read channels
450 AnimChannel<double> AttributeList::readChannelFloat(string name) {
451         if(!exists(name)) { return AnimChannel<double>(0.0); } 
452         AnimChannel<double> ret = find(name)->getChannelFloat(); 
453         find(name)->setUsed(true);
454         channelSimplifyd(ret);
455         return ret;
456 }
457 AnimChannel<int> AttributeList::readChannelInt(string name) {
458         if(!exists(name)) { return AnimChannel<int>(0); } 
459         AnimChannel<int> ret = find(name)->getChannelInt(); 
460         find(name)->setUsed(true);
461         channelSimplifyi(ret);
462         return ret;
463 }
464 AnimChannel<ntlVec3d> AttributeList::readChannelVec3d(string name) {
465         if(!exists(name)) { return AnimChannel<ntlVec3d>(0.0); } 
466         AnimChannel<ntlVec3d> ret = find(name)->getChannelVec3d(); 
467         find(name)->setUsed(true);
468         channelSimplifyVd(ret);
469         return ret;
470 }
471 AnimChannel<ntlVec3f> AttributeList::readChannelVec3f(string name) {
472         if(!exists(name)) { return AnimChannel<ntlVec3f>(0.0); } 
473
474         AnimChannel<ntlVec3d> convert = find(name)->getChannelVec3d(); 
475         // convert to float
476         vector<ntlVec3f> vals;
477         for(size_t i=0; i<convert.accessValues().size(); i++) {
478                 vals.push_back( vec2F(convert.accessValues()[i]) );
479         }
480         vector<double> times = convert.accessTimes();
481         AnimChannel<ntlVec3f> ret(vals, times);
482         find(name)->setUsed(true);
483         channelSimplifyVf(ret);
484         return ret;
485 }
486
487 /******************************************************************************
488  * destructor
489  *****************************************************************************/
490 AttributeList::~AttributeList() { 
491         for(map<string, Attribute*>::iterator i=mAttrs.begin();
492                         i != mAttrs.end(); i++) {
493                 if((*i).second) {
494                         delete (*i).second;
495                         (*i).second = NULL;
496                 }
497         }
498 };
499
500
501 /******************************************************************************
502  * debugging
503  *****************************************************************************/
504
505 //! debug function, prints value 
506 void Attribute::print()
507 {
508         std::ostringstream ostr;
509         ostr << "ATTR "<< mName <<"= ";
510         for(size_t i=0;i<mValue.size();i++) {
511                 ostr <<"'"<< mValue[i]<<"' ";
512         }
513         if(mIsChannel) {
514                 ostr << " CHANNEL: ";
515                 if(mChannelInited>0) {
516                 for(size_t i=0;i<mChannel.size();i++) {
517                         for(size_t j=0;j<mChannel[i].size();j++) {
518                                 ostr <<"'"<< mChannel[i][j]<<"' ";
519                         }
520                         ostr << "@"<<mTimes[i]<<"; ";
521                 }
522                 } else {
523                         ostr <<" -nyi- ";
524                 }                       
525         }
526         ostr <<" (at line "<<mLine<<") "; //<< std::endl;
527         debugOut( ostr.str(), 10);
528 }
529                 
530 //! debug function, prints all attribs 
531 void AttributeList::print()
532 {
533         debugOut("Attribute "<<mName<<" values:", 10);
534         for(map<string, Attribute*>::iterator i=mAttrs.begin();
535                         i != mAttrs.end(); i++) {
536                 if((*i).second) {
537                         (*i).second->print();
538                 }
539         }
540 }
541
542
543 /******************************************************************************
544  * import attributes from other attribute list
545  *****************************************************************************/
546 void AttributeList::import(AttributeList *oal)
547 {
548         for(map<string, Attribute*>::iterator i=oal->mAttrs.begin();
549                         i !=oal->mAttrs.end(); i++) {
550                 // FIXME - check freeing of copyied attributes
551                 if((*i).second) {
552                         Attribute *newAttr = new Attribute( *(*i).second );
553                         mAttrs[ (*i).first ] = newAttr;
554                 }
555         }
556 }
557
558
559 /******************************************************************************
560  * channel max finding
561  *****************************************************************************/
562 ntlVec3f channelFindMaxVf (AnimChannel<ntlVec3f> channel) {
563         ntlVec3f ret(0.0);
564         float maxLen = 0.0;
565         for(size_t i=0; i<channel.accessValues().size(); i++) {
566                 float nlen = normNoSqrt(channel.accessValues()[i]);
567                 if(nlen>maxLen) { ret=channel.accessValues()[i]; maxLen=nlen; }
568         }
569         return ret;
570 }
571 ntlVec3d channelFindMaxVd (AnimChannel<ntlVec3d> channel) {
572         ntlVec3d ret(0.0);
573         float maxLen = 0.0;
574         for(size_t i=0; i<channel.accessValues().size(); i++) {
575                 float nlen = normNoSqrt(channel.accessValues()[i]);
576                 if(nlen>maxLen) { ret=channel.accessValues()[i]; maxLen=nlen; }
577         }
578         return ret;
579 }
580 int      channelFindMaxi  (AnimChannel<float   > channel) {
581         int ret = 0;
582         float maxLen = 0.0;
583         for(size_t i=0; i<channel.accessValues().size(); i++) {
584                 float nlen = ABS(channel.accessValues()[i]);
585                 if(nlen>maxLen) { ret= (int)channel.accessValues()[i]; maxLen=nlen; }
586         }
587         return ret;
588 }
589 float    channelFindMaxf  (AnimChannel<float   > channel) {
590         float ret = 0.0;
591         float maxLen = 0.0;
592         for(size_t i=0; i<channel.accessValues().size(); i++) {
593                 float nlen = ABS(channel.accessValues()[i]);
594                 if(nlen>maxLen) { ret=channel.accessValues()[i]; maxLen=nlen; }
595         }
596         return ret;
597 }
598 double   channelFindMaxd  (AnimChannel<double  > channel) {
599         double ret = 0.0;
600         float maxLen = 0.0;
601         for(size_t i=0; i<channel.accessValues().size(); i++) {
602                 float nlen = ABS(channel.accessValues()[i]);
603                 if(nlen>maxLen) { ret=channel.accessValues()[i]; maxLen=nlen; }
604         }
605         return ret;
606 }
607
608 /******************************************************************************
609  // unoptimized channel simplification functions, use elbeem.cpp functions
610  // warning - currently only with single precision
611  *****************************************************************************/
612
613 template<class SCALAR>
614 static bool channelSimplifyScalarT(AnimChannel<SCALAR> &channel) {
615         int   size = channel.getSize();
616         if(size<=1) return false;
617         float *nchannel = new float[2*size];
618         if(DEBUG_CHANNELS) errMsg("channelSimplifyf","S" << channel.printChannel() );
619         // convert to array
620         for(size_t i=0; i<channel.accessValues().size(); i++) {
621                 nchannel[i*2 + 0] = (float)channel.accessValues()[i];
622                 nchannel[i*2 + 1] = (float)channel.accessTimes()[i];
623         }
624         bool ret = elbeemSimplifyChannelFloat(nchannel, &size);
625         if(ret) {
626                 vector<SCALAR> vals;
627                 vector<double> times;
628                 for(int i=0; i<size; i++) {
629                         vals.push_back(  (SCALAR)(nchannel[i*2 + 0]) );
630                         times.push_back( (double)(nchannel[i*2 + 1]) );
631                 }
632                 channel = AnimChannel<SCALAR>(vals, times);
633                 if(DEBUG_CHANNELS) errMsg("channelSimplifyf","C" << channel.printChannel() );
634         }
635         delete [] nchannel;
636         return ret;
637 }
638 bool channelSimplifyi  (AnimChannel<int   > &channel) { return channelSimplifyScalarT<int>(channel); }
639 bool channelSimplifyf  (AnimChannel<float> &channel) { return channelSimplifyScalarT<float>(channel); }
640 bool channelSimplifyd  (AnimChannel<double  > &channel) { return channelSimplifyScalarT<double>(channel); }
641 template<class VEC>
642 static bool channelSimplifyVecT(AnimChannel<VEC> &channel) {
643         int   size = channel.getSize();
644         if(size<=1) return false;
645         float *nchannel = new float[4*size];
646         if(DEBUG_CHANNELS) errMsg("channelSimplifyf","S" << channel.printChannel() );
647         // convert to array
648         for(size_t i=0; i<channel.accessValues().size(); i++) {
649                 nchannel[i*4 + 0] = (float)channel.accessValues()[i][0];
650                 nchannel[i*4 + 1] = (float)channel.accessValues()[i][1];
651                 nchannel[i*4 + 2] = (float)channel.accessValues()[i][2];
652                 nchannel[i*4 + 3] = (float)channel.accessTimes()[i];
653         }
654         bool ret = elbeemSimplifyChannelVec3(nchannel, &size);
655         if(ret) {
656                 vector<VEC> vals;
657                 vector<double> times;
658                 for(int i=0; i<size; i++) {
659                         vals.push_back(  VEC(nchannel[i*4 + 0], nchannel[i*4 + 1], nchannel[i*4 + 2] ) );
660                         times.push_back( (double)(nchannel[i*4 + 3]) );
661                 }
662                 channel = AnimChannel<VEC>(vals, times);
663                 if(DEBUG_CHANNELS) errMsg("channelSimplifyf","C" << channel.printChannel() );
664         }
665         delete [] nchannel;
666         return ret;
667 }
668 bool channelSimplifyVf (AnimChannel<ntlVec3f> &channel) {
669         return channelSimplifyVecT<ntlVec3f>(channel);
670 }
671 bool channelSimplifyVd (AnimChannel<ntlVec3d> &channel) {
672         return channelSimplifyVecT<ntlVec3d>(channel);
673 }
674
675 template<class Scalar>
676 string AnimChannel<Scalar>::printChannel() {
677         std::ostringstream ostr;
678         ostr << " CHANNEL #"<<  mValue.size() <<" = { ";
679         for(size_t i=0;i<mValue.size();i++) {
680                 ostr <<"'"<< mValue[i]<<"' ";
681                 ostr << "@"<<mTimes[i]<<"; ";
682         }
683         ostr << " } ";
684         return ostr.str();
685 } // */
686
687
688