- another minor solver update to fix
[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                 setElbeemState( -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                 setElbeemState( -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                 setElbeemState( -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                 setElbeemState( -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 //! get channel as float vector set
353 AnimChannel<ntlSetVec3f> 
354 Attribute::getChannelSetVec3f() {
355         vector<double> timeVec;
356         ntlSetVec3f setv;
357         vector< ntlSetVec3f > valVec;
358         
359         if((!initChannel(3)) || (!mIsChannel)) {
360                 timeVec.push_back( 0.0 );
361                 setv.mVerts.push_back( vec2F( getAsVec3d() ) );
362                 valVec.push_back( setv );
363         } else {
364                 for(size_t i=0; i<mChannel.size(); i++) {
365                         mValue = mChannel[i];
366                         ntlVec3f val = vec2F( getAsVec3d() );
367                         timeVec.push_back( mTimes[i] );
368                         setv.mVerts.push_back( val );
369                 }
370                 valVec.push_back( setv );
371                 valVec.push_back( setv );
372         }
373
374         return AnimChannel<ntlSetVec3f>(valVec,timeVec);
375 }
376
377 /******************************************************************************
378  * check if there were unknown params
379  *****************************************************************************/
380 bool AttributeList::checkUnusedParams()
381 {
382         bool found = false;
383         for(map<string, Attribute*>::iterator i=mAttrs.begin();
384                         i != mAttrs.end(); i++) {
385                 if((*i).second) {
386                         if(!(*i).second->getUsed()) {
387                                 errMsg("AttributeList::checkUnusedParams", "List "<<mName<<" has unknown parameter '"<<(*i).first<<"' = '"<< mAttrs[(*i).first]->getAsString(true) <<"' ");
388                                 found = true;
389                         }
390                 }
391         }
392         return found;
393 }
394 //! set all params to used, for invisible objects
395 void AttributeList::setAllUsed() {
396         for(map<string, Attribute*>::iterator i=mAttrs.begin();
397                         i != mAttrs.end(); i++) {
398                 if((*i).second) {
399                         (*i).second->setUsed(true);
400                 }
401         }
402 }
403
404 /******************************************************************************
405  * Attribute list read functions
406  *****************************************************************************/
407 int AttributeList::readInt(string name, int defaultValue, string source,string target, bool needed) {
408         if(!exists(name)) {
409                 if(needed) { errFatal("AttributeList::readInt","Required attribute '"<<name<<"' for "<< source <<"  not set! ", SIMWORLD_INITERROR); }
410                 return defaultValue;
411         } 
412         if(DEBUG_ATTRIBUTES==1) { debugOut( source << " Var '"<< target <<"' set to '"<< find(name)->getCompleteString() <<"' as type int " , 3); }
413         find(name)->setUsed(true);
414         return find(name)->getAsInt(); 
415 }
416 bool AttributeList::readBool(string name, bool defaultValue, string source,string target, bool needed) {
417         if(!exists(name)) {
418                 if(needed) { errFatal("AttributeList::readBool","Required attribute '"<<name<<"' for "<< source <<"  not set! ", SIMWORLD_INITERROR); }
419                 return defaultValue;
420         } 
421         if(DEBUG_ATTRIBUTES==1) { debugOut( source << " Var '"<< target <<"' set to '"<< find(name)->getCompleteString() <<"' as type int " , 3); }
422         find(name)->setUsed(true);
423         return find(name)->getAsBool(); 
424 }
425 double AttributeList::readFloat(string name, double defaultValue, string source,string target, bool needed) {
426         if(!exists(name)) {
427                 if(needed) { errFatal("AttributeList::readFloat","Required attribute '"<<name<<"' for "<< source <<"  not set! ", SIMWORLD_INITERROR); }
428                 return defaultValue;
429         } 
430         if(DEBUG_ATTRIBUTES==1) { debugOut( source << " Var '"<< target <<"' set to '"<< find(name)->getCompleteString() <<"' as type int " , 3); }
431         find(name)->setUsed(true);
432         return find(name)->getAsFloat(); 
433 }
434 string AttributeList::readString(string name, string defaultValue, string source,string target, bool needed) {
435         if(!exists(name)) {
436                 if(needed) { errFatal("AttributeList::readInt","Required attribute '"<<name<<"' for "<< source <<"  not set! ", SIMWORLD_INITERROR); }
437                 return defaultValue;
438         } 
439         if(DEBUG_ATTRIBUTES==1) { debugOut( source << " Var '"<< target <<"' set to '"<< find(name)->getCompleteString() <<"' as type int " , 3); }
440         find(name)->setUsed(true);
441         return find(name)->getAsString(false); 
442 }
443 ntlVec3d AttributeList::readVec3d(string name, ntlVec3d defaultValue, string source,string target, bool needed) {
444         if(!exists(name)) {
445                 if(needed) { errFatal("AttributeList::readInt","Required attribute '"<<name<<"' for "<< source <<"  not set! ", SIMWORLD_INITERROR); }
446                 return defaultValue;
447         } 
448         if(DEBUG_ATTRIBUTES==1) { debugOut( source << " Var '"<< target <<"' set to '"<< find(name)->getCompleteString() <<"' as type int " , 3); }
449         find(name)->setUsed(true);
450         return find(name)->getAsVec3d(); 
451 }
452
453 void AttributeList::readMat4Gfx(string name, ntlMat4Gfx defaultValue, string source,string target, bool needed, ntlMat4Gfx *mat) {
454         if(!exists(name)) {
455                 if(needed) { errFatal("AttributeList::readInt","Required attribute '"<<name<<"' for "<< source <<"  not set! ", SIMWORLD_INITERROR); }
456                 *mat = defaultValue;
457                 return;
458         } 
459         if(DEBUG_ATTRIBUTES==1) { debugOut( source << " Var '"<< target <<"' set to '"<< find(name)->getCompleteString() <<"' as type int " , 3); }
460         find(name)->setUsed(true);
461         find(name)->getAsMat4Gfx( mat ); 
462         return;
463 }
464
465 // set that a parameter can be given, and will be ignored...
466 bool AttributeList::ignoreParameter(string name, string source) {
467         if(!exists(name)) return false;
468         find(name)->setUsed(true);
469         if(DEBUG_ATTRIBUTES==1) { debugOut( source << " Param '"<< name <<"' set but ignored... " , 3); }
470         return true;
471 }
472                 
473 // read channels
474 AnimChannel<int> AttributeList::readChannelInt(string name, int defaultValue, string source, string target, bool needed) {
475         if(!exists(name)) { 
476                 if(needed) { errFatal("AttributeList::readChannelInt","Required channel '"<<name<<"' for "<<target<<" from "<< source <<"  not set! ", SIMWORLD_INITERROR); }
477                 return AnimChannel<int>(defaultValue); } 
478         AnimChannel<int> ret = find(name)->getChannelInt(); 
479         find(name)->setUsed(true);
480         channelSimplifyi(ret);
481         return ret;
482 }
483 AnimChannel<double> AttributeList::readChannelFloat(string name, double defaultValue, string source, string target, bool needed ) {
484         if(!exists(name)) {
485                 if(needed) { errFatal("AttributeList::readChannelFloat","Required channel '"<<name<<"' for "<<target<<" from "<< source <<"  not set! ", SIMWORLD_INITERROR); }
486                 return AnimChannel<double>(defaultValue); } 
487         AnimChannel<double> ret = find(name)->getChannelFloat(); 
488         find(name)->setUsed(true);
489         channelSimplifyd(ret);
490         return ret;
491 }
492 AnimChannel<ntlVec3d> AttributeList::readChannelVec3d(string name, ntlVec3d defaultValue, string source, string target, bool needed ) {
493         if(!exists(name)) { 
494                 if(needed) { errFatal("AttributeList::readChannelVec3d","Required channel '"<<name<<"' for "<<target<<" from "<< source <<"  not set! ", SIMWORLD_INITERROR); }
495                 return AnimChannel<ntlVec3d>(defaultValue); } 
496         AnimChannel<ntlVec3d> ret = find(name)->getChannelVec3d(); 
497         find(name)->setUsed(true);
498         channelSimplifyVd(ret);
499         return ret;
500 }
501 AnimChannel<ntlSetVec3f> AttributeList::readChannelSetVec3f(string name, ntlSetVec3f defaultValue, string source, string target, bool needed) {
502         if(!exists(name)) { 
503                 if(needed) { errFatal("AttributeList::readChannelSetVec3f","Required channel '"<<name<<"' for "<<target<<" from "<< source <<"  not set! ", SIMWORLD_INITERROR); }
504                 return AnimChannel<ntlSetVec3f>(defaultValue); } 
505         AnimChannel<ntlSetVec3f> ret = find(name)->getChannelSetVec3f(); 
506         find(name)->setUsed(true);
507         //channelSimplifyVf(ret);
508         return ret;
509 }
510 AnimChannel<float> AttributeList::readChannelSinglePrecFloat(string name, float defaultValue, string source, string target, bool needed ) {
511         if(!exists(name)) { 
512                 if(needed) { errFatal("AttributeList::readChannelSinglePrecFloat","Required channel '"<<name<<"' for "<<target<<" from "<< source <<"  not set! ", SIMWORLD_INITERROR); }
513                 return AnimChannel<float>(defaultValue); } 
514         AnimChannel<double> convert = find(name)->getChannelFloat(); 
515         find(name)->setUsed(true);
516         channelSimplifyd(convert);
517         // convert to float vals
518         vector<float> vals;
519         for(size_t i=0; i<convert.accessValues().size(); i++) {
520                 vals.push_back( (float)(convert.accessValues()[i]) );
521         }
522         vector<double> times = convert.accessTimes();
523         AnimChannel<float> ret(vals, times);
524         return ret;
525 }
526 AnimChannel<ntlVec3f> AttributeList::readChannelVec3f(string name, ntlVec3f defaultValue, string source, string target, bool needed) {
527         if(!exists(name)) { 
528                 if(needed) { errFatal("AttributeList::readChannelVec3f","Required channel '"<<name<<"' for "<<target<<" from "<< source <<"  not set! ", SIMWORLD_INITERROR); }
529                 return AnimChannel<ntlVec3f>(defaultValue); } 
530
531         AnimChannel<ntlVec3d> convert = find(name)->getChannelVec3d(); 
532         // convert to float
533         vector<ntlVec3f> vals;
534         for(size_t i=0; i<convert.accessValues().size(); i++) {
535                 vals.push_back( vec2F(convert.accessValues()[i]) );
536         }
537         vector<double> times = convert.accessTimes();
538         AnimChannel<ntlVec3f> ret(vals, times);
539         find(name)->setUsed(true);
540         channelSimplifyVf(ret);
541         return ret;
542 }
543
544 /******************************************************************************
545  * destructor
546  *****************************************************************************/
547 AttributeList::~AttributeList() { 
548         for(map<string, Attribute*>::iterator i=mAttrs.begin();
549                         i != mAttrs.end(); i++) {
550                 if((*i).second) {
551                         delete (*i).second;
552                         (*i).second = NULL;
553                 }
554         }
555 };
556
557
558 /******************************************************************************
559  * debugging
560  *****************************************************************************/
561
562 //! debug function, prints value 
563 void Attribute::print()
564 {
565         std::ostringstream ostr;
566         ostr << "ATTR "<< mName <<"= ";
567         for(size_t i=0;i<mValue.size();i++) {
568                 ostr <<"'"<< mValue[i]<<"' ";
569         }
570         if(mIsChannel) {
571                 ostr << " CHANNEL: ";
572                 if(mChannelInited>0) {
573                 for(size_t i=0;i<mChannel.size();i++) {
574                         for(size_t j=0;j<mChannel[i].size();j++) {
575                                 ostr <<"'"<< mChannel[i][j]<<"' ";
576                         }
577                         ostr << "@"<<mTimes[i]<<"; ";
578                 }
579                 } else {
580                         ostr <<" -nyi- ";
581                 }                       
582         }
583         ostr <<" (at line "<<mLine<<") "; //<< std::endl;
584         debugOut( ostr.str(), 10);
585 }
586                 
587 //! debug function, prints all attribs 
588 void AttributeList::print()
589 {
590         debugOut("Attribute "<<mName<<" values:", 10);
591         for(map<string, Attribute*>::iterator i=mAttrs.begin();
592                         i != mAttrs.end(); i++) {
593                 if((*i).second) {
594                         (*i).second->print();
595                 }
596         }
597 }
598
599
600 /******************************************************************************
601  * import attributes from other attribute list
602  *****************************************************************************/
603 void AttributeList::import(AttributeList *oal)
604 {
605         for(map<string, Attribute*>::iterator i=oal->mAttrs.begin();
606                         i !=oal->mAttrs.end(); i++) {
607                 // FIXME - check freeing of copyied attributes
608                 if((*i).second) {
609                         Attribute *newAttr = new Attribute( *(*i).second );
610                         mAttrs[ (*i).first ] = newAttr;
611                 }
612         }
613 }
614
615
616 /******************************************************************************
617  * channel max finding
618  *****************************************************************************/
619 ntlVec3f channelFindMaxVf (AnimChannel<ntlVec3f> channel) {
620         ntlVec3f ret(0.0);
621         float maxLen = 0.0;
622         for(size_t i=0; i<channel.accessValues().size(); i++) {
623                 float nlen = normNoSqrt(channel.accessValues()[i]);
624                 if(nlen>maxLen) { ret=channel.accessValues()[i]; maxLen=nlen; }
625         }
626         return ret;
627 }
628 ntlVec3d channelFindMaxVd (AnimChannel<ntlVec3d> channel) {
629         ntlVec3d ret(0.0);
630         float maxLen = 0.0;
631         for(size_t i=0; i<channel.accessValues().size(); i++) {
632                 float nlen = normNoSqrt(channel.accessValues()[i]);
633                 if(nlen>maxLen) { ret=channel.accessValues()[i]; maxLen=nlen; }
634         }
635         return ret;
636 }
637 int      channelFindMaxi  (AnimChannel<float   > channel) {
638         int ret = 0;
639         float maxLen = 0.0;
640         for(size_t i=0; i<channel.accessValues().size(); i++) {
641                 float nlen = ABS(channel.accessValues()[i]);
642                 if(nlen>maxLen) { ret= (int)channel.accessValues()[i]; maxLen=nlen; }
643         }
644         return ret;
645 }
646 float    channelFindMaxf  (AnimChannel<float   > channel) {
647         float ret = 0.0;
648         float maxLen = 0.0;
649         for(size_t i=0; i<channel.accessValues().size(); i++) {
650                 float nlen = ABS(channel.accessValues()[i]);
651                 if(nlen>maxLen) { ret=channel.accessValues()[i]; maxLen=nlen; }
652         }
653         return ret;
654 }
655 double   channelFindMaxd  (AnimChannel<double  > channel) {
656         double ret = 0.0;
657         float maxLen = 0.0;
658         for(size_t i=0; i<channel.accessValues().size(); i++) {
659                 float nlen = ABS(channel.accessValues()[i]);
660                 if(nlen>maxLen) { ret=channel.accessValues()[i]; maxLen=nlen; }
661         }
662         return ret;
663 }
664
665 /******************************************************************************
666  // unoptimized channel simplification functions, use elbeem.cpp functions
667  // warning - currently only with single precision
668  *****************************************************************************/
669
670 template<class SCALAR>
671 static bool channelSimplifyScalarT(AnimChannel<SCALAR> &channel) {
672         int   size = channel.getSize();
673         if(size<=1) return false;
674         float *nchannel = new float[2*size];
675         if(DEBUG_CHANNELS) errMsg("channelSimplifyf","S" << channel.printChannel() );
676         // convert to array
677         for(size_t i=0; i<channel.accessValues().size(); i++) {
678                 nchannel[i*2 + 0] = (float)channel.accessValues()[i];
679                 nchannel[i*2 + 1] = (float)channel.accessTimes()[i];
680         }
681         bool ret = elbeemSimplifyChannelFloat(nchannel, &size);
682         if(ret) {
683                 vector<SCALAR> vals;
684                 vector<double> times;
685                 for(int i=0; i<size; i++) {
686                         vals.push_back(  (SCALAR)(nchannel[i*2 + 0]) );
687                         times.push_back( (double)(nchannel[i*2 + 1]) );
688                 }
689                 channel = AnimChannel<SCALAR>(vals, times);
690                 if(DEBUG_CHANNELS) errMsg("channelSimplifyf","C" << channel.printChannel() );
691         }
692         delete [] nchannel;
693         return ret;
694 }
695 bool channelSimplifyi  (AnimChannel<int   > &channel) { return channelSimplifyScalarT<int>(channel); }
696 bool channelSimplifyf  (AnimChannel<float> &channel) { return channelSimplifyScalarT<float>(channel); }
697 bool channelSimplifyd  (AnimChannel<double  > &channel) { return channelSimplifyScalarT<double>(channel); }
698 template<class VEC>
699 static bool channelSimplifyVecT(AnimChannel<VEC> &channel) {
700         int   size = channel.getSize();
701         if(size<=1) return false;
702         float *nchannel = new float[4*size];
703         if(DEBUG_CHANNELS) errMsg("channelSimplifyf","S" << channel.printChannel() );
704         // convert to array
705         for(size_t i=0; i<channel.accessValues().size(); i++) {
706                 nchannel[i*4 + 0] = (float)channel.accessValues()[i][0];
707                 nchannel[i*4 + 1] = (float)channel.accessValues()[i][1];
708                 nchannel[i*4 + 2] = (float)channel.accessValues()[i][2];
709                 nchannel[i*4 + 3] = (float)channel.accessTimes()[i];
710         }
711         bool ret = elbeemSimplifyChannelVec3(nchannel, &size);
712         if(ret) {
713                 vector<VEC> vals;
714                 vector<double> times;
715                 for(int i=0; i<size; i++) {
716                         vals.push_back(  VEC(nchannel[i*4 + 0], nchannel[i*4 + 1], nchannel[i*4 + 2] ) );
717                         times.push_back( (double)(nchannel[i*4 + 3]) );
718                 }
719                 channel = AnimChannel<VEC>(vals, times);
720                 if(DEBUG_CHANNELS) errMsg("channelSimplifyf","C" << channel.printChannel() );
721         }
722         delete [] nchannel;
723         return ret;
724 }
725 bool channelSimplifyVf (AnimChannel<ntlVec3f> &channel) {
726         return channelSimplifyVecT<ntlVec3f>(channel);
727 }
728 bool channelSimplifyVd (AnimChannel<ntlVec3d> &channel) {
729         return channelSimplifyVecT<ntlVec3d>(channel);
730 }
731
732 //! debug function, prints channel as string
733 template<class Scalar>
734 string AnimChannel<Scalar>::printChannel() {
735         std::ostringstream ostr;
736         ostr << " CHANNEL #"<<  mValue.size() <<" = { ";
737         for(size_t i=0;i<mValue.size();i++) {
738                 ostr <<"'"<< mValue[i]<<"' ";
739                 ostr << "@"<<mTimes[i]<<"; ";
740         }
741         ostr << " } ";
742         return ostr.str();
743 } // */
744
745 //! debug function, prints to stdout if DEBUG_CHANNELS flag is enabled, used in constructors
746 template<class Scalar>
747 void AnimChannel<Scalar>::debugPrintChannel() {
748         if(DEBUG_CHANNELS) { errMsg("channelCons"," : " << this->printChannel() ); }
749 }
750
751
752 // hack to force instantiation
753 void __forceAnimChannelInstantiation() {
754         AnimChannel< float > tmp1;
755         AnimChannel< double > tmp2;
756         AnimChannel< string > tmp3;
757         AnimChannel< ntlVector3Dim<float> > tmp4;
758         tmp1.debugPrintChannel();
759         tmp2.debugPrintChannel();
760         tmp3.debugPrintChannel();
761         tmp4.debugPrintChannel();
762 }
763
764
765 ntlSetVec3f::ntlSetVec3f(double v ) {
766         mVerts.clear();
767         mVerts.push_back( ntlVec3f(v) );
768 }
769 const ntlSetVec3f& 
770 ntlSetVec3f::operator=(double v ) {
771         mVerts.clear();
772         mVerts.push_back( ntlVec3f(v) );
773         return *this;
774 }
775
776 std::ostream& operator<<( std::ostream& os, const ntlSetVec3f& vs ) {
777         os<< "{";
778         for(int j=0;j<(int)vs.mVerts.size();j++)  os<<vs.mVerts[j];
779         os<< "}";
780   return os;
781 }
782
783 ntlSetVec3f& 
784 ntlSetVec3f::operator+=( double v )
785 {
786         for(int j=0;j<(int)(mVerts.size()) ;j++) {
787                 mVerts[j] += v;
788         }
789         return *this;
790 }
791
792 ntlSetVec3f& 
793 ntlSetVec3f::operator+=( const ntlSetVec3f &v )
794 {
795         for(int j=0;j<(int)MIN(mVerts.size(),v.mVerts.size()) ;j++) {
796                 mVerts[j] += v.mVerts[j];
797         }
798         return *this;
799 }
800
801 ntlSetVec3f& 
802 ntlSetVec3f::operator*=( double v )
803 {
804         for(int j=0;j<(int)(mVerts.size()) ;j++) {
805                 mVerts[j] *= v;
806         }
807         return *this;
808 }
809
810 ntlSetVec3f& 
811 ntlSetVec3f::operator*=( const ntlSetVec3f &v )
812 {
813         for(int j=0;j<(int)MIN(mVerts.size(),v.mVerts.size()) ;j++) {
814                 mVerts[j] *= v.mVerts[j];
815         }
816         return *this;
817 }
818
819