00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "rubysceneimporter.h"
00023 #include <zeitgeist/logserver/logserver.h>
00024 #include <zeitgeist/fileserver/fileserver.h>
00025 #include <zeitgeist/scriptserver/scriptserver.h>
00026 #include <oxygen/sceneserver/transform.h>
00027 #include <boost/scoped_array.hpp>
00028
00029 using namespace zeitgeist;
00030 using namespace oxygen;
00031 using namespace boost;
00032 using namespace std;
00033
00058 #define S_NODE "node"
00059 #define S_SELECT "select"
00060 #define S_PWD "pwd"
00061 #define S_TEMPLATE "template"
00062 #define S_DEFINE "define"
00063 #define S_ATTACH "attach"
00064
00065 #define S_DELTASCENE "RubyDeltaScene"
00066 #define S_SCENEGRAPH "RubySceneGraph"
00067
00068 #define S_FROMSTRING "<from string>";
00069
00070 RubySceneImporter::RubySceneImporter() : SceneImporter()
00071 {
00072 mVersionMajor = 0;
00073 mVersionMinor = 0;
00074 mDeltaScene = false;
00075 mAutoUnlink = false;
00076 }
00077
00078 RubySceneImporter::~RubySceneImporter()
00079 {
00080 }
00081
00082 void RubySceneImporter::SetUnlinkOnCompleteScenes(bool unlink)
00083 {
00084 mAutoUnlink = unlink;
00085 }
00086
00087 bool RubySceneImporter::ImportScene(const std::string& fileName,
00088 shared_ptr<BaseNode> root,
00089 shared_ptr<ParameterList> parameter)
00090 {
00091
00092 shared_ptr<salt::RFile> file = GetFile()->Open(fileName);
00093
00094 if (file.get() == 0)
00095 {
00096 GetLog()->Error() << "(RubySceneImporter) ERROR: cannot open file '"
00097 << fileName << "'\n";
00098 return false;
00099 }
00100
00101 mFileName = fileName;
00102
00103
00104 scoped_array<char> buffer(new char[file->Size() + 1]);
00105 file->Read(buffer.get(), file->Size());
00106 buffer[file->Size()] = 0;
00107
00108 return ParseScene(buffer.get(), file->Size(), root, parameter);
00109 }
00110
00111 bool RubySceneImporter::ParseScene(const std::string& scene,
00112 shared_ptr<BaseNode> root,
00113 shared_ptr<ParameterList> parameter)
00114 {
00115 mFileName = S_FROMSTRING;
00116 return ParseScene(scene.c_str(),scene.size(),root,parameter);
00117 }
00118
00119 bool RubySceneImporter::ParseScene(const char* scene, int size,
00120 boost::shared_ptr<oxygen::BaseNode> root,
00121 boost::shared_ptr<zeitgeist::ParameterList> parameter)
00122 {
00123
00124 pcont_t* pcont = init_continuation(const_cast<char*>(scene));
00125 sexp_t* sexp = iparse_sexp(const_cast<char*>(scene),size,pcont);
00126
00127
00128 if (
00129 (sexp == 0) ||
00130 (! ReadHeader(sexp)) ||
00131 (mVersionMajor != 0) ||
00132 (mVersionMinor != 1)
00133 )
00134 {
00135 destroy_sexp(sexp);
00136 destroy_continuation(pcont);
00137 return false;
00138 }
00139
00140
00141 PushParameter(parameter);
00142
00143 destroy_sexp(sexp);
00144 sexp = iparse_sexp(const_cast<char*>(scene),size,pcont);
00145
00146 if (
00147 (! mDeltaScene) &&
00148 (mAutoUnlink)
00149 )
00150 {
00151 root->UnlinkChildren();
00152 }
00153
00154 bool ok = mDeltaScene ?
00155 ReadDeltaGraph(sexp,root) :
00156 ReadGraph(sexp,root);
00157
00158 destroy_sexp(sexp);
00159 destroy_continuation(pcont);
00160
00161 InvokeMethods();
00162 PopParameter();
00163 return ok;
00164 }
00165
00166 void RubySceneImporter::PushParameter(shared_ptr<ParameterList> parameter)
00167 {
00168 mParameterStack.push_back(ParamEnv(parameter));
00169 }
00170
00171 void RubySceneImporter::PopParameter()
00172 {
00173 if (mParameterStack.empty())
00174 {
00175 GetLog()->Debug()
00176 << "(RubySceneImporter) ERROR: PopParameter "
00177 << "called on empty stack\n";
00178 return;
00179 }
00180
00181 mParameterStack.pop_back();
00182 }
00183
00184 RubySceneImporter::ParamEnv& RubySceneImporter::GetParamEnv()
00185 {
00186 if (mParameterStack.empty())
00187 {
00188 GetLog()->Debug()
00189 << "(RubySceneImporter) ERROR: GetParamEnv "
00190 << "called on empty stack\n";
00191
00192 static ParamEnv nullEnv;
00193 return nullEnv;
00194 }
00195
00196 return mParameterStack.back();
00197 }
00198
00199 bool RubySceneImporter::ReadHeader(sexp_t* sexp)
00200 {
00201
00202 if (
00203 (sexp == 0) ||
00204 (sexp->ty != SEXP_LIST) ||
00205 (sexp->list == 0)
00206 )
00207 {
00208 return false;
00209 }
00210
00211 sexp = sexp->list;
00212 if (sexp->ty != SEXP_VALUE)
00213 {
00214 return false;
00215 }
00216
00217 string val(sexp->val);
00218
00219 mDeltaScene = false;
00220 if (val == S_DELTASCENE)
00221 {
00222 mDeltaScene = true;
00223 } else if (val != S_SCENEGRAPH)
00224 {
00225 return false;
00226 }
00227
00228
00229 sexp = sexp->next;
00230 if (
00231 (sexp == 0) ||
00232 (sexp->ty != SEXP_VALUE)
00233 )
00234 {
00235 return false;
00236 }
00237
00238 string mastr(sexp->val);
00239 int major = atoi(mastr.c_str());
00240
00241 if (major < 0)
00242 {
00243 return false;
00244 }
00245
00246 sexp = sexp->next;
00247
00248 if (
00249 (sexp == 0) ||
00250 (sexp->ty != SEXP_VALUE)
00251 )
00252 {
00253 return false;
00254 }
00255
00256 string mistr(sexp->val);
00257 int minor = atoi(mistr.c_str());
00258
00259 if (minor < 0)
00260 {
00261 return false;
00262 }
00263
00264 mVersionMajor = major;
00265 mVersionMinor = minor;
00266
00267 return true;
00268 }
00269
00270 shared_ptr<Object> RubySceneImporter::CreateInstance(const string& className)
00271 {
00272 static const string prefixes[] =
00273 {
00274 "",
00275 "oxygen/",
00276 "kerosin/"
00277 };
00278
00279 const int n = sizeof(prefixes)/sizeof(string);
00280 for (int i=0;i<n;++i)
00281 {
00282 string name = prefixes[i] + className;
00283 if (GetCore()->ExistsClass(name))
00284 {
00285 return GetCore()->New(name);
00286 }
00287 }
00288
00289 return shared_ptr<Object>();
00290 }
00291
00292 shared_ptr<BaseNode>
00293 RubySceneImporter::CreateNode(sexp_t* sexp)
00294 {
00295 if (sexp == 0)
00296 {
00297 return shared_ptr<BaseNode>();
00298 }
00299
00300 string className(sexp->val);
00301
00302
00303 shared_ptr<Object> obj = CreateInstance(className);
00304
00305 if (obj.get() == 0)
00306 {
00307 GetLog()->Error()
00308 << "(RubySceneImporter) ERROR: in file '" << mFileName
00309 << "': unknown class '"
00310 << className << "'\n";
00311 return shared_ptr<BaseNode>();
00312 }
00313
00314 shared_ptr<BaseNode> node = shared_dynamic_cast<BaseNode>(obj);
00315
00316 if (node.get() == 0)
00317 {
00318 GetLog()->Error()
00319 << "(RubySceneImporter) ERROR: in file '" << mFileName
00320 << className << "': is not derived from BaseNode'\n";
00321 return shared_ptr<BaseNode>();
00322 }
00323
00324 return node;
00325 }
00326
00327 bool RubySceneImporter::ReplaceVariable(string& param)
00328 {
00329
00330 const ParamEnv& env = GetParamEnv();
00331
00332 param.erase(param.begin(),param.begin()+1);
00333 TParameterMap::const_iterator iter = env.parameterMap.find(param);
00334
00335 if (iter == env.parameterMap.end())
00336 {
00337 GetLog()->Error()
00338 << "(RubySceneImporter) ERROR: in file '"
00339 << mFileName
00340 << "': unknown parameter '"
00341 << param << "'\n";
00342 return false;
00343 }
00344
00345 int idx = (*iter).second;
00346
00347 if (idx >= env.parameter->GetSize())
00348 {
00349 GetLog()->Error()
00350 << "(RubySceneImporter) ERROR: in file '"
00351 << mFileName
00352 << "': parameter value '"
00353 << param << "' not supplied\n";
00354 return false;
00355 }
00356
00357 string value;
00358 ParameterList::TVector::const_iterator pIter = (*env.parameter)[idx];
00359 if (! env.parameter->AdvanceValue(pIter,value))
00360 {
00361 GetLog()->Error()
00362 << "(RubySceneImporter) ERROR: in file '"
00363 << mFileName
00364 << "': failed to read parameter value '"
00365 << param << "'\n";
00366 return false;
00367 }
00368
00369 param = value;
00370 return true;
00371 }
00372
00373 bool RubySceneImporter::EvalParameter(sexp_t* sexp, string& value)
00374 {
00375 const boost::shared_ptr<ScriptServer>& script = GetScript();
00376 if (script.get() == 0)
00377 {
00378 GetLog()->Error()
00379 << "(RubySceneImporter) ERROR: in file '"
00380 << mFileName
00381 << "': cannot get ScriptServer to eval expression\n";
00382 return false;
00383 }
00384
00385 if (sexp->ty != SEXP_VALUE)
00386 {
00387 return false;
00388 }
00389
00390 string pred = sexp->val;
00391 if (pred != "eval")
00392 {
00393 GetLog()->Error()
00394 << "(RubySceneImporter) ERROR: in file '"
00395 << mFileName
00396 << "': unknown expression type '" << pred << "' in parameter list\n";
00397 return false;
00398 }
00399
00400 string expr;
00401 sexp = sexp->next;
00402 while (sexp != 0)
00403 {
00404 string atom;
00405
00406 if (sexp->ty == SEXP_VALUE)
00407 {
00408 atom = sexp->val;
00409 if (
00410 (atom[0] == '$') &&
00411 (! ReplaceVariable(atom))
00412 )
00413 {
00414 return false;
00415 }
00416 } else
00417 {
00418 if (! EvalParameter(sexp->list, atom))
00419 {
00420 return false;
00421 }
00422 }
00423
00424 expr = expr + atom;
00425 expr = expr + " ";
00426
00427 sexp = sexp->next;
00428 }
00429
00430 if (expr.empty())
00431 {
00432 GetLog()->Error()
00433 << "(RubySceneImporter) ERROR: in file '"
00434 << mFileName
00435 << "': empty eval expression in parameter list\n";
00436 return false;
00437 }
00438
00439 GCValue gcValue;
00440 if (! script->Eval(expr, gcValue))
00441 {
00442 GetLog()->Error()
00443 << "(RubySceneImporter) ERROR: in file '"
00444 << mFileName
00445 << "': failed to eval expression "
00446 << expr << "\n";
00447 return false;
00448 }
00449
00450 if (! gcValue.GetString(value))
00451 {
00452 GetLog()->Error()
00453 << "(RubySceneImporter) ERROR: in file '"
00454 << mFileName
00455 << "': failed to get string result form expresion result\n";
00456 return false;
00457 }
00458
00459 return true;
00460 }
00461
00462 void RubySceneImporter::PushInvocation(const MethodInvocation& invoc)
00463 {
00464 shared_ptr<Class> baseNodeClass =
00465 shared_dynamic_cast<Class>(GetCore()->Get("/classes/oxygen/Transform"));
00466
00467 if (baseNodeClass.get() == 0)
00468 {
00469 GetLog()->Error()
00470 << "(RubySceneImporter) ERROR: failed to get class object for Transform\n";
00471 return;
00472 }
00473
00474 if (baseNodeClass->SupportsCommand(invoc.method))
00475 {
00476
00477
00478 Invoke(invoc);
00479 } else
00480 {
00481
00482
00483
00484 ParamEnv& env = GetParamEnv();
00485 env.invocationList.push_back(invoc);
00486 }
00487 }
00488
00489 bool RubySceneImporter::Invoke(const MethodInvocation& invoc)
00490 {
00491 if (invoc.node.expired())
00492 {
00493 GetLog()->Error()
00494 << "(RubySceneImporter) ERROR: Invoke called with expired node\n";
00495 return false;
00496 }
00497
00498
00499 shared_ptr<Node> node = invoc.node.lock();
00500 shared_ptr<Class> theClass = node->GetClass();
00501
00502 if (theClass.get() == 0)
00503 {
00504 GetLog()->Error()
00505 << "(RubySceneImporter) ERROR: cannot get class object for node "
00506 << node->GetFullPath() << "\n";
00507 return false;
00508 }
00509
00510 if (! theClass->SupportsCommand(invoc.method))
00511 {
00512 GetLog()->Error()
00513 << "(RubySceneImporter) ERROR: in file '" << mFileName
00514 << "': unknown method name '"
00515 << invoc.method << "' for node '" << node->GetFullPath()
00516 << "' (a " << theClass->GetName() << ")\n";
00517 return false;
00518 }
00519
00520 node->Invoke(invoc.method, invoc.parameter);
00521 return true;
00522 }
00523
00524 bool RubySceneImporter::InvokeMethods()
00525 {
00526 RubySceneImporter::ParamEnv& env = GetParamEnv();
00527
00528 for (
00529 TMethodInvocationList::const_iterator iter = env.invocationList.begin();
00530 iter != env.invocationList.end();
00531 ++iter
00532 )
00533 {
00534 const MethodInvocation& invoc = (*iter);
00535 Invoke(invoc);
00536 }
00537 }
00538
00539 bool RubySceneImporter::ReadMethodCall(sexp_t* sexp, shared_ptr<BaseNode> node)
00540 {
00541 if (sexp == 0)
00542 {
00543 return false;
00544 }
00545
00546
00547 string method = sexp->val;
00548 sexp = sexp->next;
00549
00550
00551 MethodInvocation invocation;
00552 invocation.node = node;
00553 invocation.method = method;
00554
00555 while (sexp != 0)
00556 {
00557 string param;
00558
00559 if (sexp->ty == SEXP_LIST)
00560 {
00561 if (! EvalParameter(sexp->list,param))
00562 {
00563 return false;
00564 }
00565
00566 } else
00567 {
00568 param = sexp->val;
00569
00570 if (
00571 (param[0] == '$') &&
00572 (! ReplaceVariable(param))
00573 )
00574 {
00575 return false;
00576 }
00577 }
00578
00579 invocation.parameter.AddValue(param);
00580 sexp = sexp->next;
00581 }
00582
00583 PushInvocation(invocation);
00584 return true;
00585 }
00586
00587 bool RubySceneImporter::ParseDefine(sexp_t* sexp)
00588 {
00589 string varname = sexp->val;
00590 sexp = sexp->next;
00591
00592 if (
00593 (varname[0] != '$') ||
00594 (varname.size() < 2)
00595 )
00596 {
00597 GetLog()->Error()
00598 << "(RubySceneImporter) ERROR: in file '" << mFileName
00599 << "': parameter name expected\n";
00600 return false;
00601 }
00602
00603 varname.erase(varname.begin(),varname.begin()+1);
00604
00605 if (sexp == 0)
00606 {
00607 GetLog()->Error()
00608 << "(RubySceneImporter) ERROR: in file '"
00609 << mFileName
00610 << "': define without value\n";
00611 return false;
00612 }
00613
00614 string value;
00615 if (sexp->ty == SEXP_LIST)
00616 {
00617 if (sexp->ty == SEXP_LIST)
00618 {
00619 if (! EvalParameter(sexp->list,value))
00620 {
00621 return false;
00622 }
00623 }
00624 } else
00625 {
00626 value = sexp->val;
00627
00628 if (
00629 (value[0] == '$') &&
00630 (! ReplaceVariable(value))
00631 )
00632 {
00633 return false;
00634 }
00635 }
00636
00637 ParamEnv& env = GetParamEnv();
00638 TParameterMap::const_iterator iter =
00639 env.parameterMap.find(varname);
00640
00641 if (iter == env.parameterMap.end())
00642 {
00643
00644 env.parameter->AddValue(value);
00645 env.parameterMap[varname] = (env.parameterMap.size() - 1);
00646 } else
00647 {
00648
00649 ParameterList::TVector::iterator valIter =
00650 (*env.parameter)[(*iter).second];
00651 (*valIter) = value;
00652 }
00653
00654 return true;
00655 }
00656
00657 bool RubySceneImporter::ParseTemplate(sexp_t* sexp)
00658 {
00659 if (sexp == 0)
00660 {
00661 return false;
00662 }
00663
00664 ParamEnv& env = GetParamEnv();
00665
00666 while (
00667 (sexp != 0) &&
00668 (sexp->ty == SEXP_VALUE)
00669 )
00670 {
00671 string param = sexp->val;
00672
00673 if (param.size() == 0)
00674 {
00675 sexp = sexp->next;
00676 continue;
00677 }
00678
00679 if (
00680 (param[0] != '$') ||
00681 (param.size() < 2)
00682 )
00683 {
00684 GetLog()->Error()
00685 << "(RubySceneImporter) ERROR: in file '" << mFileName
00686 << "': template parameter name expected\n";
00687 return false;
00688 }
00689
00690 param.erase(param.begin(),param.begin()+1);
00691 TParameterMap::const_iterator iter = env.parameterMap.find(param);
00692
00693 if (iter != env.parameterMap.end())
00694 {
00695 GetLog()->Error()
00696 << "(RubySceneImporter) ERROR: in file '" << mFileName
00697 << "': duplicate template parameter name '" << param << "'\n";
00698 return false;
00699 }
00700
00701 int idx = env.parameterMap.size();
00702 env.parameterMap[param] = idx;
00703 sexp = sexp->next;
00704 }
00705
00706 return true;
00707 }
00708
00709 bool
00710 RubySceneImporter::ReadDeltaGraph(sexp_t* sexp, shared_ptr<BaseNode> root)
00711 {
00712 TLeafList::const_iterator iter = root->begin();
00713
00714 while (sexp != 0)
00715 {
00716 switch (sexp->ty)
00717 {
00718 case SEXP_VALUE:
00719 {
00720 string name(sexp->val);
00721
00722 if (name == S_NODE)
00723 {
00724 while (
00725 (sexp != 0) &&
00726 (sexp->ty != SEXP_LIST)
00727 )
00728 {
00729 sexp = sexp->next;
00730 }
00731 continue;
00732 } else {
00733 return ReadMethodCall(sexp, root);
00734 }
00735 }
00736 break;
00737 case SEXP_LIST:
00738 {
00739 sexp_t* sub = sexp->list;
00740 if (sub != 0)
00741 {
00742 shared_ptr<BaseNode> node;
00743
00744 if (
00745 (sub->ty == SEXP_VALUE) &&
00746 (string(sub->val) == S_NODE)
00747 )
00748 {
00749 node = shared_dynamic_cast<BaseNode>(*iter);
00750 if (iter != node->end())
00751 {
00752 ++iter;
00753 }
00754 } else {
00755 node = root;
00756 }
00757
00758 if (! ReadDeltaGraph(sub, node))
00759 {
00760 return false;
00761 }
00762 }
00763 }
00764 break;
00765 default:
00766 return false;
00767
00768 }
00769 sexp = sexp->next;
00770 }
00771 return true;
00772 }
00773
00774 bool
00775 RubySceneImporter::ReadGraph(sexp_t* sexp, shared_ptr<BaseNode> root)
00776 {
00777 while (sexp != 0)
00778 {
00779 switch (sexp->ty)
00780 {
00781 case SEXP_VALUE:
00782 {
00783 string name(sexp->val);
00784
00785 if (name == S_NODE)
00786 {
00787 sexp = sexp->next;
00788 shared_ptr<BaseNode> node = CreateNode(sexp);
00789
00790 if (node.get() == 0)
00791 {
00792 return false;
00793 }
00794
00795 root->AddChildReference(node);
00796 root = node;
00797 }
00798 else if (name == S_SELECT)
00799 {
00800 sexp = sexp->next;
00801 string name(sexp->val);
00802
00803 shared_ptr<BaseNode> node =
00804 shared_dynamic_cast<BaseNode>(root->GetChild(name));
00805
00806 if (node.get() == 0)
00807 {
00808 GetLog()->Error() << "ERROR: Select: " << name << " not found\n";
00809 return false;
00810 }
00811 root = node;
00812 }
00813 else if (name == S_PWD)
00814 {
00815 GetLog()->Debug() << "DEBUG: pwd: " << root->GetFullPath() << "\n";
00816 }
00817 else if (name == S_TEMPLATE)
00818 {
00819 sexp = sexp->next;
00820 return ParseTemplate(sexp);
00821 }
00822 else if (name == S_DEFINE)
00823 {
00824 sexp = sexp->next;
00825 return ParseDefine(sexp);
00826 } else {
00827 return ReadMethodCall(sexp, root);
00828 }
00829 }
00830 break;
00831
00832 case SEXP_LIST:
00833 if (! ReadGraph(sexp->list,root))
00834 {
00835 return false;
00836 }
00837 break;
00838
00839 default:
00840 return false;
00841 }
00842 sexp = sexp->next;
00843 }
00844 return true;
00845 }
00846
00847
00848
00849