material 08-Default
{
technique
{
pass
{
ambient 0.588235 0.588235 0.588235 1
diffuse 0.588235 0.588235 0.588235 1
specular 0 0 0 1 10
texture_unit
{
texture liuxing1.bmp
}
}
}
}
上述材質腳本,OGRE 解析是在如下函數中
bool ScriptCompiler::compile(const String &str, const String &source, const String &group)
{
ScriptLexer lexer;
ScriptParser parser;
ConcreteNodeListPtr nodes = parser.parse(lexer.tokenize(str, source));
return compile(nodes, group);
}
輸入的 str 就是最上邊的材質腳本,已經處理為一個字元串。整個解析分3步。
1、lexer.tokenize(str, source))。進行詞法分析,輸出為一個詞數組。結構為:
/** This struct represents a token, which is an ID'd lexeme from the
parsing input stream.
*/
struct ScriptToken
{
/// This is the lexeme for this token
String lexeme, file;
/// This is the id associated with the lexeme, which comes from a lexeme-token id mapping
uint32 type;
/// This holds the line number of the input stream where the token was found.
uint32 line;
};
typedef SharedPtr<ScriptToken> ScriptTokenPtr;
typedef vector<ScriptTokenPtr>::type ScriptTokenList;
typedef SharedPtr<ScriptTokenList> ScriptTokenListPtr;
處理的字元數組剔除了空格,保留了換行符(10)。處理的字元數組剔除了空格,保留了換行符(10)。處理的字元數組剔除了空格,保留了換行符(10)。
2、parser.parse()。進行類似CST(Concrete Syntax Tree) 分析,輸出為一個文法節點,結構如下:
/** The ConcreteNode is the struct that holds an un-conditioned sub-tree of parsed input */
struct ConcreteNode;
typedef SharedPtr<ConcreteNode> ConcreteNodePtr;
typedef list<ConcreteNodePtr>::type ConcreteNodeList;
typedef SharedPtr<ConcreteNodeList> ConcreteNodeListPtr;
struct ConcreteNode : public ScriptCompilerAlloc
{
String token, file;
unsigned int line;
ConcreteNodeType type;
ConcreteNodeList children;
ConcreteNode *parent;
};
該文法樹已經剔除了換行符,輸出節點執行個體如下:
material
--- 08-Default
---{ 父節點A
---}
父節點A
technique
--- { 父節點B
--- }
父節點B
pass
--- { 父節點C
--- }
父節點C
--- ambient
--- 0.588235
--- 0.588235
--- 0.588235
--- 1
--- diffuse
--- 0.588235
--- 0.588235
--- 0.588235
--- 1
--- specular
--- 0
--- 0
--- 0
--- 1
--- 10
--- texture_unit
--- { 父節點D
--- }
父節點D
texture
--- liuxing1.bmp
3、return compile(nodes, group)。實際包含兩步:進行類似AST(Abstract Syntax Tree) 分析; 之後把AST資訊轉化為Material。
3.1 AST。所用的結構為:
class _OgreExport AbstractNode : public AbstractNodeAlloc
{
public:
String file;
unsigned int line;
AbstractNodeType type;
AbstractNode *parent;
Any context; // A holder for translation context data
public:
AbstractNode(AbstractNode *ptr);
virtual ~AbstractNode(){}
/// Returns a new AbstractNode which is a replica of this one.
virtual AbstractNode *clone() const = 0;
/// Returns a string value depending on the type of the AbstractNode.
virtual String getValue() const = 0;
};
context 為 Any 類型, 在3.2步根據具體的類型進行相應的轉換。
它有衆多子類,列舉幾個:
/** This specific abstract node represents a script object */
class _OgreExport ObjectAbstractNode : public AbstractNode
{
private:
map<String,String>::type mEnv;
public:
String name, cls;
std::vector<String> bases;
uint32 id;
bool abstract;
AbstractNodeList children;
AbstractNodeList values;
AbstractNodeList overrides; // For use when processing object inheritance and overriding
public:
ObjectAbstractNode(AbstractNode *ptr);
AbstractNode *clone() const;
String getValue() const;
void addVariable(const String &name);
void setVariable(const String &name, const String &value);
std::pair<bool,String> getVariable(const String &name) const;
const map<String,String>::type &getVariables() const;
};
其中 name = "08-Default", cls 即類名 material, id 為該類的标志ID。
/** This abstract node represents a script property */
class _OgreExport PropertyAbstractNode : public AbstractNode
{
public:
String name;
uint32 id;
AbstractNodeList values;
public:
PropertyAbstractNode(AbstractNode *ptr);
AbstractNode *clone() const;
String getValue() const;
};
以及
/** This is an abstract node which cannot be broken down further */
class _OgreExport AtomAbstractNode : public AbstractNode
{
public:
String value;
uint32 id;
public:
AtomAbstractNode(AbstractNode *ptr);
AbstractNode *clone() const;
String getValue() const;
private:
void parseNumber() const;
};
經過 AbstractNodeListPtr ast = convertToAST(nodes); 處理後,材質腳本執行個體為
1> ObjectAbstractNode .
name = "08-Default", cls="material", id = 3. child 指向下一級, 有1個子節點。
2> ObjectAbstractNode .
name = "", cls="technique", id = 7. child 指向下一級, 有1個子節點。
3> ObjectAbstractNode .
name = "", cls="pass", id = 8. child 指向下一級, 有4個子節點。
4> PropertyAbstractNode. 有3個,分别為 ambient, diffuse, specular
name = "ambient", id = 37. values 有4個值,指向下一級。
ObjectAbstractNode . 有一個,即紋理
name = "", cls="texture_unit", id = 9. child 指向下一級, 有1個子節點, 為PropertyAbstractNode,不再列舉了。
5> AtomAbstractNode
value = "0.588235", id = 0.
3.2 做了2件事。
A 獲得AbstractNode對應的ScriptTranslator:
ScriptTranslator *translator = ScriptCompilerManager::getSingleton().getTranslator(*i);
B 根據ScriptTranslator 生成 material。注意:生成的material各相關量儲存在AbstractNode的Any類型的變量context中。
CSDN 真垃圾,編輯器現在又亂了,代碼和普通文字已經區分不開。