OGRE脚本解析流程分析--扫描阶段
Ogre的脚本解析分为以下步骤:
TOKEN化阶段
这个阶段主要是进行预处理,忽略空格并去掉注释,并将有用的脚本数据整理到ScriptTokenList结构中以供下阶段使用。
在OgreScriptLexer.cpp 中有一函数ScriptLexer::tokenize完成此功能。
这里有两个关键的数据结构
//Token结构
struct ScriptToken
{
String lexeme; //token内容
String file; //脚本文件名
uint32 type; //token类型
uint32 line; //token所在文件行号
}
typedef SharedPtr<ScriptToken> ScriptTokenPtr;
//Token容器
typedef vector<ScriptTokenPtr>::type ScriptTokenList;
比如example.program中有如下数据
//example 脚本
vertex_program AmbientOneTexture cg
{
source Example_Basic.cg
}
token化后,ScriptTokenList中每一个ScriptToken结构中的lexeme成员为如下数据:
"vertex_program",
"AmbientOneTexture",
"cg",
"{",
"source",
"Example_Basic.cg",
"}"
PARSE阶段
token阶段只是将有用的数据存入ScriptTokenList,数据之间仅仅是线性平行关系。在PARSE阶段,Ogre将数据进一步处理,形成树状层次关系
还是先介绍该阶段的基本数据结构
struct ConcreteNode:public ScriptCompilerAlloc
{
String token,file;
unsigned int line;
ConcreteNodeType type;
ConcreteNodeList children;
ConcreteNode* parent;
};
typedef SharedPtr<ConcreteNode> ConcreteNodePtr;
typedef list<ConcreteNodePtr>::type ConcreteNodeList;
很显然,PARSE阶段实质上就是生成ConcreteNodeList数据。
材质脚本解析
分析之前先简单介绍下材质脚本的结构。一个典型的material脚本如下:
material Core/NodeMaterial
{
technique
{
pass
{
lighting off
scene_blend add
depth_check off
depth_write off
cull_hardware none
texture_unit
{
texture axes.png
}
}
}
}
可见,material是一个层次结构,一个material可以包含若干个technique,一个technique包含若干个pass,一个pass包含若干个texture,一个texture对应一张picture。
材质脚本解析器读取*.material文件,生成相应的Material对象,并读取其中的technique,pass,赋值给材质对象(Material)统一管理。所以,Ogre的Shader由材质对象(Material)管理。
解析material文件主要由两个函数完成:
void MaterialSerializer::parseScript(DataStreamPtr& stream,const String& groupName)
bool MaterialSerializer::parseScriptLine(String& line)
经过这两个函数的处理,系统就已经把material脚本读取并生成material对象,并添加到resourcegroup以备以后加载资源和渲染。注意,material中的材质单元在解析阶段默认是不会加载到显存中的。