00001 /*************************************************************************** 00002 * * 00003 * (c) Art Tevs, MPI Informatik Saarbruecken * 00004 * mailto: <tevs@mpi-sb.mpg.de> * 00005 * * 00006 * This program is free software; you can redistribute it and/or modify * 00007 * it under the terms of the GNU General Public License as published by * 00008 * the Free Software Foundation; either version 2 of the License, or * 00009 * (at your option) any later version. * 00010 * * 00011 ***************************************************************************/ 00012 00013 00014 #ifndef _NR_SCRIPT_RESOURCE__H_ 00015 #define _NR_SCRIPT_RESOURCE__H_ 00016 00017 00018 //---------------------------------------------------------------------------------- 00019 // Includes 00020 //---------------------------------------------------------------------------------- 00021 #include "Prerequisities.h" 00022 #include "IScript.h" 00023 00024 namespace nrEngine{ 00025 00026 00027 //! Simple script object based on engine's simple script language 00028 /** 00029 * This is a simple script language object. We use this language as engine's 00030 * default one to load other more powerfull script languages. This languages 00031 * could be found in plugins. 00032 * 00033 * Also simple scripts can be used to setup some variables or to write config 00034 * files that will be used to setup the engine's environment. This config files 00035 * could also contains plugins loading and file system setup. So actually this 00036 * simple language is enough to write simple applications. 00037 * 00038 * The scripts have very simple syntax: 00039 * - each line is a script command 00040 * - the line is bypassed to the script engine (so commands must be registered or it will cause no effect) 00041 * - one command per one frame (if not other specified) 00042 * - commands can be bound to a certain time (execute command at this time) 00043 * - time values are always relative to the start time of the script 00044 * - nontimed commands are executed sequentially 00045 * - timed commands are executed quasi parallel to the nontimed 00046 * - if one script calls another one, so the new one runs in parallel 00047 * 00048 * 00049 * Example of such a script (I called this timeline scripts): 00050 * 00051 * seq_command param1 // execute seq_command sequantially with param1 as first argument 00052 * 1.452 | cmd1 par1 // execute the command cmd1 with parameter par1 at the time 1.452s (after starting of the script) 00053 * 1.693 | run script/script2.tml // execute script script/script2.tml after the time reaches 1.693 00054 * 00055 * Scripts could include subscripts. Subscripts are defined between 00056 * {} - brackets. The string between this brackets is used as a scipts 00057 * as if it was used in an explicit file. So the string is parsed 00058 * as a script and runs also parallel to the parent script. For timed 00059 * and non-timed commands the same restrictions are used as in non-subscripts. 00060 * Subscripts could define new subscripts. Because scripts are running as task, 00061 * we add a task dependency between parent script and subscript. So parent script 00062 * depends on subscript. This means parent script can only step forward after 00063 * subscripts has done their steps. 00064 * 00065 * NOTE: 00066 * - We represent each script as a task, so the scripts are running in parallel 00067 * - This type of script can run stepwise which is default behaviour. Specify it in 00068 * another way if you want to run the script completely in one frame. 00069 * 00070 * @see IScript 00071 * \ingroup script 00072 **/ 00073 class _NRExport Script : public IScript{ 00074 public: 00075 00076 //! Allocate memory and initilize simple script 00077 Script(); 00078 00079 //! Deallocate memory and release used data 00080 ~Script(); 00081 00082 00083 /** 00084 * Load simple script language from a string. 00085 * @copydoc IScript::loadFromString() 00086 **/ 00087 Result loadFromString(const std::string& str); 00088 00089 /** 00090 * Execute the script completely. So the script will be 00091 * executed until it finishes. This function will lock the execution 00092 * of the engine while the script is running. 00093 * 00094 * NOTE: Timed commands used in nrScript would not been executed 00095 * here. This is because of the time which will not be updated 00096 * while the script is running. Updating the time, means either to 00097 * update the clock or the kernel. This is not allowed by tasks, 00098 * it means tasks can not update them self only kernel can do this. 00099 * 00100 * So if you call execute() so only sequential commands will be 00101 * executed! 00102 * 00103 * NOTE: Be carefull by using looped scripts. If there is a loop, so the 00104 * script will also be executed in loop mode, so if you do not stop it 00105 * somehow your application could not react anymore!!! 00106 * If the script is looped, so warnign will be printed in a log file! 00107 **/ 00108 Result fullRun(); 00109 00110 /** 00111 * Set if this script should run stepwise or completely in 00112 * one cycle. If you run the script stepwise, so each line 00113 * of the script is executed in one kernel cycle. Also time commands 00114 * are getting executed as soon, as according time is passed. 00115 * 00116 * If you run the script fully in one cycle, so look to fullRun() 00117 **/ 00118 NR_FORCEINLINE void setRunStepwise(bool b) { bRunStepwise = b; } 00119 00120 /** 00121 * Check whenever the script is running stepwise 00122 **/ 00123 NR_FORCEINLINE bool isRunStepwise() const { return bRunStepwise; } 00124 00125 private: 00126 00127 //! Return true if pipeline is full 00128 bool hasCommands(); 00129 00130 //! Script was started 00131 void onStartScript(); 00132 00133 //! Derived from IScript 00134 Result run(); 00135 00136 //! Parse the given string as nrScript language 00137 Result parse(const std::string&); 00138 00139 //! Remove all comments and empty lines from the script 00140 std::string cleanScript(const std::string&); 00141 00142 //! Parse subscripts and return non-sub-script back 00143 std::string parseSubscripts(const std::string&); 00144 00145 //! Set certain parameter from the script 00146 bool setParameter(const std::string& param, const std::vector<std::string>& args); 00147 00148 //! Reset the sequentiall command fifo 00149 void resetCommandFifo(); 00150 00151 //! Reset the timed command fifo 00152 void resetTimedCommandFifo(bool firstReset = false); 00153 00154 //! Tokenize the given line into command and arguments 00155 void tokenize(const std::string& line, std::string& cmd, std::vector<std::string>& args); 00156 00157 //! Reset the command lists (if return false, so the task is removed from kernel) 00158 bool reset(); 00159 00160 //! Script is valid 00161 bool mValid; 00162 00163 //! Error in line 00164 int32 mLastLine; 00165 00166 //! Subscripts which belongs to this one 00167 std::vector<ResourcePtr<IScript> > mSubscripts; 00168 00169 //! Time script have to stop after this duration 00170 float32 mRunningTimeLength; 00171 00172 //! Time when script started 00173 float32 mStopTime; 00174 00175 //! Run teh script stepwise 00176 bool bRunStepwise; 00177 00178 //! Each command has this type 00179 typedef struct _cmd{ 00180 00181 //! Timestamp ( = 0 -> command is not timed 00182 float32 timestamp; 00183 00184 //! estimated starting time based on the global clock time 00185 float32 estimatedStart; 00186 00187 //! current time of the command 00188 float32 time; 00189 00190 //! function name 00191 std::string cmd; 00192 00193 //! arguments of the command 00194 std::vector<std::string> args; 00195 00196 } Command; 00197 00198 //! Here we store our timed commands 00199 std::vector< Command > mTimedCommand; 00200 00201 //! Here we store our sequentiall commands 00202 std::vector< Command > mCommand; 00203 00204 //! Store command queue of waiting command ids 00205 std::list< int32 > mCommandFifo; 00206 00207 //! Store timed commands sorted by their time in the queue 00208 std::list< int32 > mTimedCommandFifo; 00209 00210 //! Script looping modes 00211 typedef enum _loopMode{ 00212 NO_LOOP = 0, 00213 LOOP_COMMAND = 1 << 0, 00214 LOOP_TIMED_COMMAND = 1 << 1, 00215 LOOP = LOOP_COMMAND | LOOP_TIMED_COMMAND 00216 } LoopMode; 00217 00218 //! Looping mode 00219 int32 mLoop; 00220 00221 //! Current time of the script 00222 float32 mTime; 00223 00224 //! Does script run to the first time 00225 bool mFirstRunTimed; 00226 00227 //! Timer used by the script (usefull for timed commands) 00228 SharedPtr<Timer> mTimer; 00229 00230 //! Specified script starting time (ala absolute time start) 00231 float32 mScriptStartTime; 00232 00233 //! Run only one step from the script 00234 Result step(); 00235 00236 }; 00237 00238 00239 }; 00240 00241 #endif