Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members

rubysceneimporter.cpp

Go to the documentation of this file.
00001 /* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*-
00002 
00003    this file is part of rcssserver3D
00004    Fri May 9 2003
00005    Copyright (C) 2002,2003 Koblenz University
00006    Copyright (C) 2003 RoboCup Soccer Server 3D Maintenance Group
00007    $Id: rubysceneimporter.cpp,v 1.12 2005/12/18 17:52:32 rollmark Exp $
00008 
00009    This program is free software; you can redistribute it and/or modify
00010    it under the terms of the GNU General Public License as published by
00011    the Free Software Foundation; version 2 of the License.
00012 
00013    This program is distributed in the hope that it will be useful,
00014    but WITHOUT ANY WARRANTY; without even the implied warranty of
00015    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016    GNU General Public License for more details.
00017 
00018    You should have received a copy of the GNU General Public License
00019    along with this program; if not, write to the Free Software
00020    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
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     // try to open the file
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     // read entire file into a temporary buffer
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     // parse s-expressions
00124     pcont_t* pcont = init_continuation(const_cast<char*>(scene));
00125     sexp_t* sexp = iparse_sexp(const_cast<char*>(scene),size,pcont);
00126 
00127     // read scene magic and version
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     // advance to next sexpression- the scene graph
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     // (RubySceneGraph <int majorVersion> <int minorVersion>)
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     // try to advance to version number
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     // create a class instance
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     // replace a template parameter
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             // invoke basic methods, i.e. methods already supported by
00477             // Transform immediately (e.g. setName, setLocalPos etc.)
00478             Invoke(invoc);
00479         } else
00480         {
00481             // defer methods on other nodes, to allow for forward
00482             // references to nodes that are not installed yet
00483             // (e.g. 'attach' on Joint nodes)
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     // invoke the method on the object
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     // read the method name
00547     string method = sexp->val;
00548     sexp = sexp->next;
00549 
00550     // build method invocation struct
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             // create a new variable
00644             env.parameter->AddValue(value);
00645             env.parameterMap[varname] = (env.parameterMap.size() - 1);
00646         } else
00647         {
00648             // update value of existing variable
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 

Generated on Thu Apr 6 15:25:39 2006 for rcssserver3d by  doxygen 1.4.4