8689a3fe98ed978daf8325aef74b7ddd645a2e50
[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 <sstream>
12
13
14 //! output attribute values? on=1/off=0
15 #define DEBUG_ATTRIBUTES 0
16
17
18 /******************************************************************************
19  * attribute conversion functions
20  *****************************************************************************/
21
22 bool Attribute::initChannel(int elemSize) {
23         if(!mIsChannel) return true;
24         if(mChannelInited==elemSize) {
25                 // already inited... ok
26                 return true;
27         } else {
28                 // sanity check
29                 if(mChannelInited>0) {
30                         errMsg("Attribute::initChannel","Duplicate channel init!? ("<<mChannelInited<<" vs "<<elemSize<<")...");
31                         return false;
32                 }
33         }
34         
35         if((mValue.size() % (elemSize+1)) !=  0) {
36                 errMsg("Attribute::initChannel","Invalid # elements in Attribute...");
37                 return false;
38         }
39         
40         int numElems = mValue.size()/(elemSize+1);
41         vector<string> newvalue;
42         for(int i=0; i<numElems; i++) {
43         //errMsg("ATTR"," i"<<i<<" "<<mName); // debug
44
45                 vector<string> elem(elemSize);
46                 for(int j=0; j<elemSize; j++) {
47                 //errMsg("ATTR"," j"<<j<<" "<<mValue[i*(elemSize+1)+j]  ); // debug
48                         elem[j] = mValue[i*(elemSize+1)+j];
49                 }
50                 mChannel.push_back(elem);
51                 // use first value as default
52                 if(i==0) newvalue = elem;
53                 
54                 double t = 0.0; // similar to getAsFloat
55                 const char *str = mValue[i*(elemSize+1)+elemSize].c_str();
56                 char *endptr;
57                 t = strtod(str, &endptr);
58                 if((str!=endptr) && (*endptr != '\0')) return false;
59                 mTimes.push_back(t);
60                 //errMsg("ATTR"," t"<<t<<" "); // debug
61         }
62         for(int i=0; i<numElems-1; i++) {
63                 if(mTimes[i]>mTimes[i+1]) {
64                         errMsg("Attribute::initChannel","Invalid time at entry "<<i<<" setting to "<<mTimes[i]);
65                         mTimes[i+1] = mTimes[i];
66                 }
67         }
68
69         // dont change until done with parsing, and everythings ok
70         mValue = newvalue;
71
72         mChannelInited = elemSize;
73         print();
74         return true;
75 }
76
77 // get value as string 
78 string Attribute::getAsString()
79 {
80         if(mIsChannel) {
81                 errMsg("Attribute::getAsString", "Attribute \"" << mName << "\" used as string is a channel! Not allowed...");
82                 print();
83                 return string("");
84         }
85         if(mValue.size()!=1) {
86                 //errMsg("Attribute::getAsString", "Attribute \"" << mName << "\" used as string has invalid value '"<< getCompleteString() <<"' ");
87                 // for directories etc. , this might be valid! cutoff "..." first
88                 string comp = getCompleteString();
89                 if(comp.size()<2) return string("");
90                 return comp.substr(1, comp.size()-2);
91         }
92         return mValue[0];
93 }
94
95 // get value as integer value
96 int Attribute::getAsInt()
97 {
98         bool success = true;
99         int ret = 0;
100
101         if(!initChannel(1)) success=false; 
102         if(success) {
103                 if(mValue.size()!=1) success = false;
104                 else {
105                         const char *str = mValue[0].c_str();
106                         char *endptr;
107                         ret = strtol(str, &endptr, 10);
108                         if( (str==endptr) ||
109                                         ((str!=endptr) && (*endptr != '\0')) )success = false;
110                 }
111         }
112
113         if(!success) {
114                 errMsg("Attribute::getAsInt", "Attribute \"" << mName << "\" used as int has invalid value '"<< getCompleteString() <<"' ");
115                 errMsg("Attribute::getAsInt", "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" );
116                 errMsg("Attribute::getAsInt", "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" );
117 #if ELBEEM_PLUGIN!=1
118                 gElbeemState = -4; // parse error
119 #endif
120                 return 0;
121         }
122         return ret;
123 }
124
125
126 // get value as integer value
127 bool Attribute::getAsBool() 
128 {
129         int val = getAsInt();
130         if(val==0) return false;
131         else                     return true;
132 }
133
134
135 // get value as double value
136 double Attribute::getAsFloat()
137 {
138         bool success = true;
139         double ret = 0.0;
140
141         if(!initChannel(1)) success=false; 
142         if(success) {
143                 if(mValue.size()!=1) success = false;
144                 else {
145                         const char *str = mValue[0].c_str();
146                         char *endptr;
147                         ret = strtod(str, &endptr);
148                         if((str!=endptr) && (*endptr != '\0')) success = false;
149                 }
150         }
151
152         if(!success) {
153                 print();
154                 errMsg("Attribute::getAsFloat", "Attribute \"" << mName << "\" used as double has invalid value '"<< getCompleteString() <<"' ");
155                 errMsg("Attribute::getAsFloat", "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" );
156                 errMsg("Attribute::getAsFloat", "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" );
157 #if ELBEEM_PLUGIN!=1
158                 gElbeemState = -4; // parse error
159 #endif
160                 return 0.0;
161         }
162         return ret;
163 }
164
165 // get value as 3d vector 
166 ntlVec3d Attribute::getAsVec3d()
167 {
168         bool success = true;
169         ntlVec3d ret(0.0);
170
171         if(!initChannel(3)) success=false; 
172         if(success) {
173                 if(mValue.size()==1) {
174                         const char *str = mValue[0].c_str();
175                         char *endptr;
176                         double rval = strtod(str, &endptr);
177                         if( (str==endptr) ||
178                                         ((str!=endptr) && (*endptr != '\0')) )success = false;
179                         if(success) ret = ntlVec3d( rval );
180                 } else if(mValue.size()==3) {
181                         char *endptr;
182                         const char *str = NULL;
183
184                         str = mValue[0].c_str();
185                         double rval1 = strtod(str, &endptr);
186                         if( (str==endptr) ||
187                                         ((str!=endptr) && (*endptr != '\0')) )success = false;
188
189                         str = mValue[1].c_str();
190                         double rval2 = strtod(str, &endptr);
191                         if( (str==endptr) ||
192                                         ((str!=endptr) && (*endptr != '\0')) )success = false;
193
194                         str = mValue[2].c_str();
195                         double rval3 = strtod(str, &endptr);
196                         if( (str==endptr) ||
197                                         ((str!=endptr) && (*endptr != '\0')) )success = false;
198
199                         if(success) ret = ntlVec3d( rval1, rval2, rval3 );
200                 } else {
201                         success = false;
202                 }
203         }
204
205         if(!success) {
206                 errMsg("Attribute::getAsVec3d", "Attribute \"" << mName << "\" used as Vec3d has invalid value '"<< getCompleteString() <<"' ");
207                 errMsg("Attribute::getAsVec3d", "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" );
208                 errMsg("Attribute::getAsVec3d", "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" );
209 #if ELBEEM_PLUGIN!=1
210                 gElbeemState = -4; // parse error
211 #endif
212                 return ntlVec3d(0.0);
213         }
214         return ret;
215 }
216                 
217 // get value as 4x4 matrix 
218 ntlMat4Gfx Attribute::getAsMat4Gfx()
219 {
220         bool success = true;
221         ntlMat4Gfx ret(0.0);
222         char *endptr;
223
224         if(mValue.size()==1) {
225                 const char *str = mValue[0].c_str();
226                 double rval = strtod(str, &endptr);
227                 if( (str==endptr) ||
228                                 ((str!=endptr) && (*endptr != '\0')) )success = false;
229                 if(success) {
230                         ret = ntlMat4Gfx( 0.0 );
231                         ret.value[0][0] = rval;
232                         ret.value[1][1] = rval;
233                         ret.value[2][2] = rval;
234                         ret.value[3][3] = 1.0;
235                 }
236         } else if(mValue.size()==9) {
237                 // 3x3
238                 for(int i=0; i<3;i++) {
239                         for(int j=0; j<3;j++) {
240                                 const char *str = mValue[i*3+j].c_str();
241                                 ret.value[i][j] = strtod(str, &endptr);
242                                 if( (str==endptr) ||
243                                                 ((str!=endptr) && (*endptr != '\0')) ) success = false;
244                         }
245                 }
246         } else if(mValue.size()==16) {
247                 // 4x4
248                 for(int i=0; i<4;i++) {
249                         for(int j=0; j<4;j++) {
250                                 const char *str = mValue[i*4+j].c_str();
251                                 ret.value[i][j] = strtod(str, &endptr);
252                                 if( (str==endptr) ||
253                                                 ((str!=endptr) && (*endptr != '\0')) ) success = false;
254                         }
255                 }
256
257         } else {
258                 success = false;
259         }
260
261         if(!success) {
262                 errMsg("Attribute::getAsMat4Gfx", "Attribute \"" << mName << "\" used as Mat4x4 has invalid value '"<< getCompleteString() <<"' ");
263                 errMsg("Attribute::getAsMat4Gfx", "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" );
264                 errMsg("Attribute::getAsMat4Gfx", "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" );
265 #if ELBEEM_PLUGIN!=1
266                 gElbeemState = -4; // parse error
267 #endif
268                 return ntlMat4Gfx(0.0);
269         }
270         return ret;
271 }
272                 
273
274 // get the concatenated string of all value string
275 string Attribute::getCompleteString()
276 {
277         string ret;
278         for(size_t i=0;i<mValue.size();i++) {
279                 ret += mValue[i];
280                 if(i<mValue.size()-1) ret += " ";
281         }
282         return ret;
283 }
284
285
286 /******************************************************************************
287  * channel returns
288  *****************************************************************************/
289
290 //! get channel as double value
291 AnimChannel<double> Attribute::getChannelFloat() {
292         vector<double> timeVec;
293         vector<double> valVec;
294         
295         if((!initChannel(1)) || (!mIsChannel)) {
296                 timeVec.push_back( 0.0 );
297                 valVec.push_back( getAsFloat() );
298         } else {
299         for(size_t i=0; i<mChannel.size(); i++) {
300                 mValue = mChannel[i];
301                 double val = getAsFloat();
302                 timeVec.push_back( mTimes[i] );
303                 valVec.push_back( val );
304         }}
305
306         return AnimChannel<double>(valVec,timeVec);
307 }
308
309 //! get channel as integer value
310 AnimChannel<int> Attribute::getChannelInt() { 
311         vector<double> timeVec;
312         vector<int> valVec;
313         
314         if((!initChannel(1)) || (!mIsChannel)) {
315                 timeVec.push_back( 0.0 );
316                 valVec.push_back( getAsInt() );
317         } else {
318         for(size_t i=0; i<mChannel.size(); i++) {
319                 mValue = mChannel[i];
320                 int val = getAsInt();
321                 timeVec.push_back( mTimes[i] );
322                 valVec.push_back( val );
323         }}
324
325         return AnimChannel<int>(valVec,timeVec);
326 }
327
328 //! get channel as integer value
329 AnimChannel<ntlVec3d> Attribute::getChannelVec3d() { 
330         vector<double> timeVec;
331         vector<ntlVec3d> valVec;
332         
333         if((!initChannel(3)) || (!mIsChannel)) {
334                 timeVec.push_back( 0.0 );
335                 valVec.push_back( getAsVec3d() );
336         } else {
337         for(size_t i=0; i<mChannel.size(); i++) {
338                 mValue = mChannel[i];
339                 ntlVec3d val = getAsVec3d();
340                 timeVec.push_back( mTimes[i] );
341                 valVec.push_back( val );
342         }}
343
344         return AnimChannel<ntlVec3d>(valVec,timeVec);
345 }
346
347
348 /******************************************************************************
349  * check if there were unknown params
350  *****************************************************************************/
351 bool AttributeList::checkUnusedParams()
352 {
353         bool found = false;
354         for(map<string, Attribute*>::iterator i=mAttrs.begin();
355                         i != mAttrs.end(); i++) {
356                 if((*i).second) {
357                         if(!(*i).second->getUsed()) {
358                                 errMsg("AttributeList::checkUnusedParams", "List "<<mName<<" has unknown parameter '"<<(*i).first<<"' = '"<< mAttrs[(*i).first]->getAsString() <<"' ");
359                                 found = true;
360                         }
361                 }
362         }
363         return found;
364 }
365 //! set all params to used, for invisible objects
366 void AttributeList::setAllUsed() {
367         for(map<string, Attribute*>::iterator i=mAttrs.begin();
368                         i != mAttrs.end(); i++) {
369                 if((*i).second) {
370                         (*i).second->setUsed(true);
371                 }
372         }
373 }
374
375 /******************************************************************************
376  * Attribute list read functions
377  *****************************************************************************/
378 int AttributeList::readInt(string name, int defaultValue, string source,string target, bool needed) {
379         if(!exists(name)) {
380                 if(needed) { errFatal("AttributeList::readInt","Required attribute '"<<name<<"' for "<< source <<"  not set! ", SIMWORLD_INITERROR); }
381                 return defaultValue;
382         } 
383         if(DEBUG_ATTRIBUTES==1) { debugOut( source << " Var '"<< target <<"' set to '"<< find(name)->getCompleteString() <<"' as type int " , 3); }
384         find(name)->setUsed(true);
385         return find(name)->getAsInt(); 
386 }
387 bool AttributeList::readBool(string name, bool defaultValue, string source,string target, bool needed) {
388         if(!exists(name)) {
389                 if(needed) { errFatal("AttributeList::readBool","Required attribute '"<<name<<"' for "<< source <<"  not set! ", SIMWORLD_INITERROR); }
390                 return defaultValue;
391         } 
392         if(DEBUG_ATTRIBUTES==1) { debugOut( source << " Var '"<< target <<"' set to '"<< find(name)->getCompleteString() <<"' as type int " , 3); }
393         find(name)->setUsed(true);
394         return find(name)->getAsBool(); 
395 }
396 double AttributeList::readFloat(string name, double defaultValue, string source,string target, bool needed) {
397         if(!exists(name)) {
398                 if(needed) { errFatal("AttributeList::readFloat","Required attribute '"<<name<<"' for "<< source <<"  not set! ", SIMWORLD_INITERROR); }
399                 return defaultValue;
400         } 
401         if(DEBUG_ATTRIBUTES==1) { debugOut( source << " Var '"<< target <<"' set to '"<< find(name)->getCompleteString() <<"' as type int " , 3); }
402         find(name)->setUsed(true);
403         return find(name)->getAsFloat(); 
404 }
405 string AttributeList::readString(string name, string defaultValue, string source,string target, bool needed) {
406         if(!exists(name)) {
407                 if(needed) { errFatal("AttributeList::readInt","Required attribute '"<<name<<"' for "<< source <<"  not set! ", SIMWORLD_INITERROR); }
408                 return defaultValue;
409         } 
410         if(DEBUG_ATTRIBUTES==1) { debugOut( source << " Var '"<< target <<"' set to '"<< find(name)->getCompleteString() <<"' as type int " , 3); }
411         find(name)->setUsed(true);
412         return find(name)->getAsString(); 
413 }
414 ntlVec3d AttributeList::readVec3d(string name, ntlVec3d defaultValue, string source,string target, bool needed) {
415         if(!exists(name)) {
416                 if(needed) { errFatal("AttributeList::readInt","Required attribute '"<<name<<"' for "<< source <<"  not set! ", SIMWORLD_INITERROR); }
417                 return defaultValue;
418         } 
419         if(DEBUG_ATTRIBUTES==1) { debugOut( source << " Var '"<< target <<"' set to '"<< find(name)->getCompleteString() <<"' as type int " , 3); }
420         find(name)->setUsed(true);
421         return find(name)->getAsVec3d(); 
422 }
423
424 ntlMat4Gfx AttributeList::readMat4Gfx(string name, ntlMat4Gfx defaultValue, string source,string target, bool needed) {
425         if(!exists(name)) {
426                 if(needed) { errFatal("AttributeList::readInt","Required attribute '"<<name<<"' for "<< source <<"  not set! ", SIMWORLD_INITERROR); }
427                 return defaultValue;
428         } 
429         if(DEBUG_ATTRIBUTES==1) { debugOut( source << " Var '"<< target <<"' set to '"<< find(name)->getCompleteString() <<"' as type int " , 3); }
430         find(name)->setUsed(true);
431         return find(name)->getAsMat4Gfx(); 
432 }
433
434 // set that a parameter can be given, and will be ignored...
435 bool AttributeList::ignoreParameter(string name, string source) {
436         if(!exists(name)) return false;
437         find(name)->setUsed(true);
438         if(DEBUG_ATTRIBUTES==1) { debugOut( source << " Param '"<< name <<"' set but ignored... " , 3); }
439         return true;
440 }
441                 
442 // read channels
443 AnimChannel<double> AttributeList::readChannelFloat(string name) {
444         if(!exists(name)) { return AnimChannel<double>(0.0); } 
445         return find(name)->getChannelFloat(); 
446 }
447 AnimChannel<int> AttributeList::readChannelInt(string name) {
448         if(!exists(name)) { return AnimChannel<int>(0); } 
449         return find(name)->getChannelInt(); 
450 }
451 AnimChannel<ntlVec3d> AttributeList::readChannelVec3d(string name) {
452         if(!exists(name)) { return AnimChannel<ntlVec3d>(0.0); } 
453         return find(name)->getChannelVec3d(); 
454 }
455
456 /******************************************************************************
457  * destructor
458  *****************************************************************************/
459 AttributeList::~AttributeList() { 
460         for(map<string, Attribute*>::iterator i=mAttrs.begin();
461                         i != mAttrs.end(); i++) {
462                 if((*i).second) {
463                         delete (*i).second;
464                         (*i).second = NULL;
465                 }
466         }
467 };
468
469
470 /******************************************************************************
471  * debugging
472  *****************************************************************************/
473
474 //! debug function, prints value 
475 void Attribute::print()
476 {
477         std::ostringstream ostr;
478         ostr << "ATTR "<< mName <<"= ";
479         for(size_t i=0;i<mValue.size();i++) {
480                 ostr <<"'"<< mValue[i]<<"' ";
481         }
482         if(mIsChannel) {
483                 ostr << " CHANNEL: ";
484                 if(mChannelInited>0) {
485                 for(size_t i=0;i<mChannel.size();i++) {
486                         for(size_t j=0;j<mChannel[i].size();j++) {
487                                 ostr <<"'"<< mChannel[i][j]<<"' ";
488                         }
489                         ostr << "@"<<mTimes[i]<<"; ";
490                 }
491                 } else {
492                         ostr <<" -nyi- ";
493                 }                       
494         }
495         ostr <<" (at line "<<mLine<<") "; //<< std::endl;
496         debugOut( ostr.str(), 10);
497 }
498                 
499 //! debug function, prints all attribs 
500 void AttributeList::print()
501 {
502         debugOut("Attribute "<<mName<<" values:", 10);
503         for(map<string, Attribute*>::iterator i=mAttrs.begin();
504                         i != mAttrs.end(); i++) {
505                 if((*i).second) {
506                         (*i).second->print();
507                 }
508         }
509 }
510
511
512
513 /******************************************************************************
514  * import attributes from other attribute list
515  *****************************************************************************/
516 void AttributeList::import(AttributeList *oal)
517 {
518         for(map<string, Attribute*>::iterator i=oal->mAttrs.begin();
519                         i !=oal->mAttrs.end(); i++) {
520                 // FIXME - check freeing of copyied attributes
521                 if((*i).second) {
522                         Attribute *newAttr = new Attribute( *(*i).second );
523                         mAttrs[ (*i).first ] = newAttr;
524                 }
525         }
526 }
527
528
529
530