boost的spirit库解析相对简单的DSL语言非常方便.以下是我解析ogre的材质脚本的代码.
这是解析代码.主要使用grammer.注意comment grammer类的使用方法,非常有用.
View Code
#ifndef _material_parser_h #define _material_parser_h #include "stdafx.h" /************************************************************************/ // boost grammer // 具体的语法解析 /************************************************************************/ #include "material_define.h" namespace client { template<class Iter> struct comment_grammer : public qi::grammar<Iter> { qi::rule<Iter> _skipper; comment_grammer() : comment_grammer::base_type(_skipper) { using qi::eol; using qi::omit; using ascii::char_; using ascii::space; using qi::lit; _skipper = omit[lit("//") >> *(char_ - eol)] | space ; } }; struct error_handler_grammer { template<typename, typename, typename> struct result { typedef void type; }; template<typename Iter> void operator() (const qi::info & what, Iter err_pos, Iter last) const { std::cout << "Error! Expecting " << what << " here: \"" << std::string(err_pos, last) << "\"" << std::endl; } }; boost::phoenix::function<error_handler_grammer> const error_handler = error_handler_grammer(); template<class Iter> struct mat_grammer : public qi::grammar<Iter, matlist(), comment_grammer<Iter>> { qi::rule<Iter, matlist(), comment_grammer<Iter> > _mat_query; qi::rule<Iter, mat_material(), comment_grammer<Iter> > _mat_mat; qi::rule<Iter, mat_technique(), comment_grammer<Iter> > _mat_tech; qi::rule<Iter, mat_pass(), comment_grammer<Iter> > _mat_pass; qi::rule<Iter, mat_shader_fragment(), comment_grammer<Iter> > _mat_shader_fragment; qi::rule<Iter, mat_shader_vertex(), comment_grammer<Iter> > _mat_shader_vertex; qi::rule<Iter, mat_texunit(), comment_grammer<Iter> > _mat_texunit; qi::rule<Iter, mat_attribute(), comment_grammer<Iter> > _mat_attr; qi::rule<Iter, std::string(), std::string() > _name, _attr; //qi::rule<Iter, std::string()> _skipper; mat_grammer():mat_grammer::base_type(_mat_query) { using qi::eps; using qi::lexeme; using qi::lit; using qi::omit; using qi::eol; using qi::no_skip; using qi::on_error; using ascii::char_; using ascii::alpha; using ascii::alnum; using ascii::print; using ascii::space; using phoenix::at_c; using phoenix::push_back; using qi::_1; using qi::_2; using qi::_3; using qi::_4; _name = lexeme[+(alpha | alnum | char_('_') | char_('#') | char_('/') | char_('-') | char_('(') | char_(')') | char_('.')| char_('&') | char_('\\'))]; _attr = lexeme[+(alpha | alnum | char_('.') | char_(' ') | char_('_') | char_('#') | char_('-') | char_('/') | char_('&') | char_('$') | char_('(') | char_(')') | char_('\\') )]; _mat_attr = _name >> +omit[no_skip[space - eol]] >> (_attr); _mat_texunit = lit("texture_unit") >> -_name >> lit('{') >> *_mat_attr >> lit('}'); _mat_shader_vertex = lit("vertex_program_ref") >> _name >> lit('{') >> *_mat_attr >> lit('}'); _mat_shader_fragment = lit("fragment_program_ref") >> _name >> lit('{') >> *_mat_attr >> lit('}'); _mat_pass = lit("pass") >> -_name >> lit('{') >> *( _mat_shader_vertex | _mat_shader_fragment | _mat_texunit | _mat_attr ) >> lit('}'); _mat_tech = lit("technique") >> lit('{') >> *_mat_pass >> lit('}'); _mat_mat = lit("material") >> _name >> lit('{') >> *_mat_tech >> lit('}'); _mat_query = eps >> *_mat_mat; on_error<qi::fail>(_mat_mat, error_handler(_4,_3,_2)); } }; } #endif
这是这是我们拆分材质单元的定义.
我在其中各个单元都定义了输出打印及存入文件的函数.实际上这一步同样可以用spirit中的karma库来实现输出.当时时间不允许,未能继续学习它.有兴趣的可以自行添加.
View Code
#ifndef _material_define_h #define _material_define_h #include "stdafx.h" namespace client { namespace fusion = boost::fusion; namespace qi = boost::spirit::qi; namespace phoenix = boost::phoenix; namespace ascii = boost::spirit::ascii; static int indent = 0; template<class StreamType> void printx(StreamType& os, int n) { for (int i =0; i<n; i++) os << ' '; } typedef std::vector<std::string> stringlist; ////////////////////////////////////////////////////////////////////////// struct mat_attribute { std::string name; std::string attr; //stringlist attr; friend std::ostream& operator << (std::ostream& os, const mat_attribute& object) { indent+=4; printx(os, indent); os << object.name << " " << object.attr << std::endl; indent-=4; return os; } bool operator == (const mat_attribute& other) const { if(name == other.name && attr == other.attr) return true; return false; } }; typedef std::vector<mat_attribute> attrlist; ////////////////////////////////////////////////////////////////////////// struct mat_texunit { std::string name; attrlist attr_list; mat_texunit():name("") {} void push_back(const mat_attribute& attr) { attr_list.push_back(attr); } void push_back(const std::string& attrname, const std::string& attrvalue) { mat_attribute attr; attr.name = attrname; attr.attr = attrvalue; push_back(attr); } friend std::ostream& operator << (std::ostream& os, const mat_texunit& object) { indent+=4; printx(os, indent); os << "texture_unit \n"; printx(os, indent); os << "{" << std::endl; attrlist::const_iterator it = object.attr_list.begin(); for (; it != object.attr_list.end(); ++it) os << *it; printx(os, indent); os << "}" << std::endl; indent-=4; return os; } bool operator == (const mat_texunit& other) const { if(name == other.name) { if(attr_list.size() == other.attr_list.size()) { attrlist::const_iterator it = attr_list.begin(); attrlist::const_iterator it_o = other.attr_list.begin(); for (; it != attr_list.end(); ++it) { if(*it == *it_o) { ++it_o; continue; } else return false; } return true; } } return false; } }; typedef std::vector<mat_texunit> texlist; ////////////////////////////////////////////////////////////////////////// struct mat_shader_vertex { std::string name; attrlist attr_list; mat_shader_vertex():name(""){} void push_back(const mat_attribute& attr) { attr_list.push_back(attr); } friend std::ostream& operator << (std::ostream& os, const mat_shader_vertex& object) { if(object.name.empty()) return os; indent+=4; printx(os, indent); os << "vertex_program_ref " << object.name << std::endl; printx(os, indent); os << "{" << std::endl; attrlist::const_iterator it = object.attr_list.begin(); for (; it != object.attr_list.end(); ++it) os << *it; printx(os, indent); os << "}" << std::endl; indent-=4; return os; } bool operator == (const mat_shader_vertex& other) const { if(name == other.name) { if(attr_list.size() == other.attr_list.size()) { attrlist::const_iterator it = attr_list.begin(); attrlist::const_iterator it_o = other.attr_list.begin(); for (; it != attr_list.end(); ++it) { if(*it == *it_o) { ++it_o; continue; } else return false; } return true; } } return false; } }; ////////////////////////////////////////////////////////////////////////// struct mat_shader_fragment { std::string name; attrlist attr_list; mat_shader_fragment():name(""){} void push_back(const mat_attribute& attr) { attr_list.push_back(attr); } friend std::ostream& operator << (std::ostream& os,const mat_shader_fragment& object) { if(object.name.empty()) return os; indent+=4; printx(os, indent); os << "fragment_program_ref " << object.name << std::endl; printx(os, indent); os << "{" << std::endl; attrlist::const_iterator it = object.attr_list.begin(); for (; it != object.attr_list.end(); ++it) os << *it; printx(os, indent); os << "}" << std::endl; indent-=4; return os; } bool operator == (const mat_shader_fragment& other) const { if(name == other.name) { if(attr_list.size() == other.attr_list.size()) { attrlist::const_iterator it = attr_list.begin(); attrlist::const_iterator it_o = other.attr_list.begin(); for (; it != attr_list.end(); ++it) { if(*it == *it_o) { ++it_o; continue; } else return false; } return true; } } return false; } }; typedef boost::variant<mat_attribute, mat_texunit, mat_shader_vertex, mat_shader_fragment> mat_passobject; typedef std::vector<mat_passobject> passobjectlist; struct mat_pass_printer : public boost::static_visitor<void> { std::ostream& _os; mat_pass_printer(std::ostream& os_):_os(os_) {} template<class T> void operator() (const T& t) const { _os << t ; } }; struct mat_pass_equal : public boost::static_visitor<bool> { template<class T> bool operator () (const T& ls, const T& rs) const { if(ls == rs) return true; return false; } template<class T, class U> bool operator () (const T& ls, const U& rs) const { return false; } }; ////////////////////////////////////////////////////////////////////////// struct mat_pass { std::string name; passobjectlist object_list; mat_pass():name("") {} void push_back(const std::string& attrname, const std::string& attrvalue) { mat_attribute attr; attr.name = attrname; attr.attr = attrvalue; push_back(attr); } void push_back(const mat_attribute& attr) { object_list.push_back(attr); } void push_back(const mat_texunit& tex) { object_list.push_back(tex); } void push_back(const mat_shader_vertex& sv) { object_list.push_back(sv); } void push_back(const mat_shader_fragment& sf) { object_list.push_back(sf); } friend std::ostream& operator << (std::ostream& os, mat_pass& object) { indent+=4; printx(os, indent); os << "pass " << object.name << std::endl; printx(os, indent); os << "{" << std::endl; passobjectlist::iterator it_object = object.object_list.begin(); for (; it_object != object.object_list.end(); ++it_object) { boost::apply_visitor(mat_pass_printer(os), *it_object); } printx(os, indent); os << "}" << std::endl; indent-=4; return os; } bool operator == (const mat_pass& other) const { if(name == other.name) { if(object_list.size() == other.object_list.size()) { passobjectlist::const_iterator it_object = object_list.begin(); passobjectlist::const_iterator it_object_other = other.object_list.begin(); for (; it_object != object_list.end(); ++it_object) { if( boost::apply_visitor(mat_pass_equal(),*it_object, *it_object_other) ) { ++it_object_other; continue; } else return false; } return true; } } return false; } }; typedef std::vector<mat_pass> passlist; ////////////////////////////////////////////////////////////////////////// struct mat_technique { passlist pass_list; void push_back(const mat_pass& pass) { pass_list.push_back(pass); } friend std::ostream& operator << (std::ostream& os, mat_technique& object) { indent+=4; printx(os, indent); os << "technique \n"; printx(os, indent); os << "{" << std::endl; passlist::iterator it = object.pass_list.begin(); for (; it != object.pass_list.end(); ++it) os << *it << std::endl; printx(os, indent); os << "}" << std::endl; indent-=4; return os; } bool operator == (const mat_technique& other) const { if(pass_list.size() == other.pass_list.size()) { passlist::const_iterator it = pass_list.begin(); passlist::const_iterator it_o = other.pass_list.begin(); for (; it != pass_list.end(); ++it) { if(*it == *it_o) { ++it_o; continue; } else return false; } return true; } return false; } }; typedef std::list<mat_technique> techniquelist; ////////////////////////////////////////////////////////////////////////// struct mat_material { std::string name; techniquelist tech_list; void push_back(const mat_technique& tech) { tech_list.push_back(tech); } void push_front(const mat_technique& tech) { tech_list.push_front(tech); } friend std::ostream& operator << (std::ostream& os, mat_material& object) { printx(os, indent); os << "material " << object.name << std::endl; printx(os, indent); os << "{" << std::endl; techniquelist::iterator it = object.tech_list.begin(); for (; it != object.tech_list.end(); ++it) { os << *it << std::endl; } printx(os, indent); os << "}" << std::endl; return os; } bool operator == (const mat_material& other) const { if(name == other.name) { if(tech_list.size() == other.tech_list.size()) { techniquelist::const_iterator it = tech_list.begin(); techniquelist::const_iterator it_o = other.tech_list.begin(); for (; it != tech_list.end(); ++it) { if(*it == *it_o) { ++it_o; continue; } else return false; } return true; } } return false; } }; typedef std::vector<mat_material> matlist; ////////////////////////////////////////////////////////////////////////// std::ostream& operator << (std::ostream& os, matlist& object) { matlist::iterator it_mat = object.begin(); for (; it_mat != object.end(); ++it_mat) { indent = 0; os << *it_mat << std::endl; } return os; } } ////////////////////////////////////////////////////////////////////////// //(client::stringlist, attr) BOOST_FUSION_ADAPT_STRUCT ( client::mat_attribute, (std::string, name) (std::string, attr) ) BOOST_FUSION_ADAPT_STRUCT ( client::mat_texunit, (std::string, name) (client::attrlist, attr_list) ) BOOST_FUSION_ADAPT_STRUCT ( client::mat_shader_vertex, (std::string, name) (client::attrlist, attr_list) ) BOOST_FUSION_ADAPT_STRUCT ( client::mat_shader_fragment, (std::string, name) (client::attrlist, attr_list) ) BOOST_FUSION_ADAPT_STRUCT ( client::mat_pass, (std::string, name) (client::passobjectlist, object_list) ) BOOST_FUSION_ADAPT_STRUCT ( client::mat_technique, (client::passlist, pass_list) ) BOOST_FUSION_ADAPT_STRUCT ( client::mat_material, (std::string, name) (client::techniquelist, tech_list) ) #endif
这是配置文件的解析,同样用到了spirit.
View Code
#ifndef _config_parser_h #define _config_parser_h #include "stdafx.h" namespace client { namespace config { struct item { std::string name; std::string value; }; typedef std::vector<item> item_list; struct session { std::string name; item_list itemlist; }; typedef std::vector<session> session_list; typedef std::map<std::string, item_list> session_map; } } BOOST_FUSION_ADAPT_STRUCT ( client::config::item, (std::string, name) (std::string, value) ) BOOST_FUSION_ADAPT_STRUCT ( client::config::session, (std::string, name) (client::config::item_list, itemlist) ) namespace client { namespace config { template<class Iter> struct comment_grammer : public qi::grammar<Iter> { qi::rule<Iter> _skipper; comment_grammer() : comment_grammer::base_type(_skipper) { using qi::eol; using qi::omit; using ascii::char_; using ascii::space; using qi::lit; _skipper = omit[lit("//") >> *(char_ - eol)] | space ; } }; template<class Iter> struct config_grammer : public qi::grammar< Iter, session_list(), comment_grammer<Iter> > { typedef comment_grammer<Iter> skipper; qi::rule<Iter, session_list(), skipper > _session_list; qi::rule<Iter, session(), skipper> _session; qi::rule<Iter, item(), skipper> _item; qi::rule<Iter, std::string(), std::string() > _name, _value; config_grammer():config_grammer::base_type(_session_list) { using qi::eps; using qi::lexeme; using qi::lit; using qi::no_skip; using qi::omit; using qi::eol; using ascii::char_; using ascii::alpha; using ascii::alnum; using ascii::space; _name = lexeme[+(alpha | alnum | char_('_'))]; _value = lexeme[+(alpha | alnum | char_('.') | char_(' ') | char_('_') | char_('#') | char_('-') | char_('/') | char_('&') | char_('$') | char_('(') | char_(')') | char_('\\') )]; _item = _name >> +omit[no_skip[space - eol]] >> _value; _session =lit("session") >> _name >> lit('{') >> *_item >> lit('}'); _session_list = eps >> * _session; } }; } } #endif
配置文件格式:
session include_cartoon_render { path Data\Model\character\ path Data\Model\drop\ path Data\Model\monster\ path Data\Model\npc\ path Data\Model\weapon\ } session shared_texture { file Model/share/avatar_female_k_tights.dds file Model/share/avatar_female_s_body.dds file Model/share/avatar_male_k_tights.dds file Model/share/avatar_male_s_body.dds } session exclude_uv_animation { material monster_water/monster_water }
这是使用的具体例子,里面混合了自己项目的一些特殊情况(丑陋情况,赶时间,只是个小工具).
View Code
#ifndef _filefolder_h #define _filefolder_h #include "stdafx.h" #include <map> #include <deque> #include <set> #include "material_parser.h" #include "material_define.h" #include "config_parser.h" #include "SimpleLogManager.h" #define MAX_PATH_LEN 512 typedef void(*PARSE_MATERIAL_FUNC) (const char*); struct mat_slot { mat_slot():filename(""),bShared(false) {} std::string filename; client::mat_material mat; bool bShared; }; typedef std::map<std::string, mat_slot> mat_map; mat_map g_mat_map; client::config::session_map g_session_map; PARSE_MATERIAL_FUNC parse_mat_func; std::fstream g_file_stream; char g_path[MAX_PATH_LEN]; void _recusive_dir(const char* filepath, const WIN32_FIND_DATA& FindFileData); /************************************************************************/ /* 辅助函数 */ /************************************************************************/ template<class Iter> bool be_model_dir(Iter first, Iter end, const char* spattern) { using boost::spirit::qi::lexeme; using boost::spirit::qi::lit; using boost::spirit::qi::parse; using boost::spirit::ascii::space; using boost::spirit::ascii::char_; bool r = parse(first, end, ( lexeme[(+char_)] >> lit(spattern) >>lexeme[ +(char_)] ) ); if(r && first == end) return true; else return false; } bool check_file_extension(const char* filename, char* name, char* extname) { int len = strlen(filename); int i = len; for (; i > 0; i--) { if(filename[i] == '.') { memcpy(extname, filename+i+1, len - i - 1); memcpy(name, filename, i); return true; } } return false; } const char* get_filepath_last_del(const char* fullfilename) { int len = strlen(fullfilename); int i = len; for (; i > 0; i--) { if(fullfilename[i] == '\\') { return fullfilename+i; } } return 0; } bool split_file_path(const char* fullfilename, char* filepath) { int len = strlen(fullfilename); int i = len; for (; i > 0; i--) { if(fullfilename[i] == '\\') { memcpy(filepath, fullfilename, i); return true; } } return false; } bool get_file_name(const char* fullfilename, char* filename) { int len = strlen(fullfilename); int i = len; for (; i > 0; i--) { if(fullfilename[i] == '\\') { memcpy(filename, fullfilename+i, len-i+1); return true; } } return false; } void replace_right_splash(const char*filename, char* outname) { int len = strlen(filename); int i = 0; for (; i < len; i++) { outname[i] = filename[i]; if(filename[i] == '\\') outname[i] = '/'; } outname[len] = '\0'; } /************************************************************************/ /* */ /************************************************************************/ bool be_cartoon_render(const char* filename) { client::config::session_map::iterator it_s = g_session_map.find("include_cartoon_render"); if(it_s == g_session_map.end()) return false; client::config::item_list::iterator it_i = it_s->second.begin(); for (; it_i != it_s->second.end(); ++it_i) { if(strstr(filename, it_i->value.c_str())) return true; } return false; } bool be_share_texture(const char* texturename, std::string& sharepath) { client::config::session_map::iterator it_s = g_session_map.find("shared_texture"); if(it_s == g_session_map.end()) return false; client::config::item_list::iterator it_i = it_s->second.begin(); for (; it_i != it_s->second.end(); ++it_i) { if(strstr(it_i->value.c_str(), texturename)) { sharepath = it_i->value; return true; } } return false; } bool be_uv_aniamtion(const char* materialname) { client::config::session_map::iterator it_s = g_session_map.find("exclude_uv_animation"); if(it_s == g_session_map.end()) return false; client::config::item_list::iterator it_i = it_s->second.begin(); for (; it_i != it_s->second.end(); ++it_i) { if(strcmp(it_i->value.c_str(), materialname)) return true; } return false; } struct mat_pass_texture_path_rewriter : public boost::static_visitor<void> { mat_slot& matslot; mat_pass_texture_path_rewriter(mat_slot& matslot_):matslot(matslot_) {} void operator() (client::mat_attribute& attr) const { return; } void operator() (client::mat_texunit& tex) const { if(tex.attr_list.size() == 0) return; const char* filename = matslot.filename.c_str(); client::attrlist::iterator it_attr = tex.attr_list.begin(); for (; it_attr != tex.attr_list.end(); ++it_attr) { if(it_attr->name == "texture") { std::string tempname; if(be_share_texture(it_attr->attr.c_str(), tempname)) { it_attr->attr = tempname; return;; } const char* x = strstr(filename, "\\Data\\"); const char* y = get_filepath_last_del(filename); if(x == NULL) continue; int lenp = strlen("\\Data"); if((x+lenp) == y) break; std::string relativepath(x+lenp+1, (x+(y-x)+1)); relativepath += it_attr->attr; char newname[MAX_PATH_LEN] = {'\0'}; replace_right_splash(relativepath.c_str(), newname); it_attr->attr = std::string(newname); } } return; } void operator() (client::mat_shader_vertex& sv) const { return; } void operator() (client::mat_shader_fragment& sf) const { return; } }; void join_pu_files(const char* filename) { g_file_stream.open(filename); //获取文件内容 std::filebuf * pbuf = g_file_stream.rdbuf(); long size = pbuf->pubseekoff(0, std::ios::end, std::ios::in); pbuf->pubseekpos(0, std::ios::in); char* cbuf = new char[size]; memset(cbuf, '\0', size); pbuf->sgetn(cbuf, size); g_file_stream.close(); g_file_stream.clear(); g_file_stream.open("gc.pu", std::ios_base::app); g_file_stream << cbuf; g_file_stream.close(); //g_file_stream.clear(); delete cbuf; } ////////////////////////////////////////////////////////////////////////// client::mat_pass pass_wireframe; client::mat_texunit tex_shadow_main; client::mat_texunit tex_shadow_diffuse; client::mat_shader_vertex sv_shadow; client::mat_shader_fragment sf_shadow; client::mat_pass pass_edge_extend; client::mat_attribute scheme_low; client::mat_attribute scheme_high; void global_variant_init() { //wireframe pass pass_wireframe.name = "Edges"; pass_wireframe.push_back("cull_hardware", "anticlockwise"); pass_wireframe.push_back("ambient", "0 0 0"); pass_wireframe.push_back("diffuse", "0 0 0"); pass_wireframe.push_back("polygon_mode", "wireframe"); pass_wireframe.push_back("depth_bias", "1"); //shadow texture unit tex_shadow_main.push_back("content_type", "shadow"); tex_shadow_main.push_back("tex_address_mode", "clamp"); tex_shadow_main.push_back("filtering", "none"); tex_shadow_main.push_back("tex_coord_set", "1"); //shadow texture unit tex_shadow_diffuse.push_back("texture", "Effect/shader_texture/celshading_diffuse.gif 1d"); tex_shadow_diffuse.push_back("tex_address_mode", "clamp"); tex_shadow_diffuse.push_back("filtering", "bilinear"); tex_shadow_diffuse.push_back("tex_coord_set", "2"); //shadow shader sv_shadow.name = "CelShading/ReceiverVP"; sf_shadow.name = "CelShading/ReceiverFP"; //pass edge shader client::mat_shader_vertex sv_outline; client::mat_shader_fragment sf_outline; pass_edge_extend.name = "Edges"; sv_outline.name = "CelShading/OutlineVP"; sf_outline.name = "CelShading/OutlineFP"; pass_edge_extend.object_list.push_back(sv_outline); pass_edge_extend.object_list.push_back(sf_outline); pass_edge_extend.push_back("cull_hardware", "anticlockwise"); scheme_low.name = "scheme"; scheme_low.attr = "low"; scheme_high.name = "scheme"; scheme_high.attr = "high"; } ////////////////////////////////////////////////////////////////////////// /* void rewrite_material_file(const char* filename, const client::matlist& _mats) { client::matlist mats = _mats; { client::matlist::iterator it_mat = mats.begin(); for (; it_mat != mats.end(); ++it_mat) { client::techniquelist::iterator it_tech = it_mat->tech_list.begin(); for (; it_tech != it_mat->tech_list.end(); ++it_tech) { client::passlist::iterator it_pass = it_tech->pass_list.begin(); for (; it_pass != it_tech->pass_list.end(); ++it_pass) { client::passobjectlist::iterator it_object = it_pass->object_list.begin(); for (; it_object != it_pass->object_list.end(); ++it_object) boost::apply_visitor(mat_pass_texture_path_rewriter(filename, false), *it_object); } } } } if (strstr(filename, "\\Data\\Model\\character\\") || strstr(filename, "\\Data\\Model\\drop\\") || strstr(filename, "\\Data\\Model\\monster\\") || strstr(filename, "\\Data\\Model\\npc\\") || strstr(filename, "\\Data\\Model\\weapon\\")) { client::matlist::iterator it_mat = mats.begin(); for (; it_mat != mats.end(); ++it_mat) { client::mat_technique tech = it_mat->tech_list.front(); it_mat->tech_list.front().push_back(scheme_low); it_mat->tech_list.front().push_back(pass_wireframe); if (tech.pass_list.size() == 1) { if(it_mat->name != "monster_water/monster_water") { tech.pass_list.front().object_list.push_back(tex_shadow_main); tech.pass_list.front().object_list.push_back(tex_shadow_diffuse); tech.pass_list.front().push_back(sv_shadow); tech.pass_list.front().push_back(sf_shadow); } tech.push_back(scheme_high); tech.push_back(pass_edge_extend); it_mat->push_front(tech); } } } g_file_stream.open("gc.material", std::ios_base::app); g_file_stream << mats; g_file_stream.close(); //g_file_stream.clear(); return; } */ void rewrite_material(mat_slot& matslot) { client::mat_material& mat = matslot.mat; const char* filename = matslot.filename.c_str(); client::techniquelist::iterator it_tech = mat.tech_list.begin(); for (; it_tech != mat.tech_list.end(); ++it_tech) { client::passlist::iterator it_pass = it_tech->pass_list.begin(); for (; it_pass != it_tech->pass_list.end(); ++it_pass) { client::passobjectlist::iterator it_object = it_pass->object_list.begin(); for (; it_object != it_pass->object_list.end(); ++it_object) boost::apply_visitor(mat_pass_texture_path_rewriter(matslot), *it_object); } } // if(be_cartoon_render(filename)) { client::mat_technique tech = mat.tech_list.front(); mat.tech_list.front().push_back(scheme_low); mat.tech_list.front().push_back(pass_wireframe); if (tech.pass_list.size() == 1) { if(be_uv_aniamtion(mat.name.c_str())) { tech.pass_list.front().object_list.push_back(tex_shadow_main); tech.pass_list.front().object_list.push_back(tex_shadow_diffuse); tech.pass_list.front().push_back(sv_shadow); tech.pass_list.front().push_back(sf_shadow); } tech.push_back(scheme_high); tech.push_back(pass_edge_extend); mat.push_front(tech); } } g_file_stream << mat; } void parse_model_material(const char* filename) { g_file_stream.open(filename); //获取文件内容 std::filebuf * pbuf = g_file_stream.rdbuf(); long size = pbuf->pubseekoff(0, std::ios::end, std::ios::in); pbuf->pubseekpos(0, std::ios::in); char* cbuf = new char[size]; memset(cbuf, '\0', size); pbuf->sgetn(cbuf, size); g_file_stream.close(); g_file_stream.clear(); std::string storage = cbuf; delete cbuf; //开始语法解析 typedef client::mat_grammer<std::string::const_iterator> mat_grammer_t; typedef client::comment_grammer<std::string::const_iterator> comment_grammer_t; mat_grammer_t matgrammer; client::matlist matcontainer; using boost::spirit::ascii::space; std::string::const_iterator iter = storage.begin(); std::string::const_iterator end = storage.end(); bool r = phrase_parse(iter, end, matgrammer, comment_grammer_t(), matcontainer); client::matlist::iterator it_m = matcontainer.begin(); for (; it_m != matcontainer.end(); ++it_m) { mat_map::iterator it_g = g_mat_map.find(it_m->name); if(it_g != g_mat_map.end()) { if(it_g->second.mat == *it_m) { it_g->second.bShared = true; continue; } else WARN_LOG << "\n警告! 发现材质\t " << it_m->name << "\n在下列文件中被重复定义:\n" << "[1]: " << it_g->second.filename << "\n[2]: " << filename << "\n"; } mat_slot slot; slot.filename = filename; slot.mat = *it_m; g_mat_map.insert(std::make_pair(it_m->name, slot)); } if (r && iter == end) { //rewrite_material_file(filename, matcontainer); return; } else { std::string::const_iterator some = iter+40; std::string context(iter, (some>end)?end:some); ERROR_LOG << "-------------------------\n"; ERROR_LOG << "解析失败\n"; ERROR_LOG << "停止在文件:\t" << (const char*)filename << "\n\"" << (const char*)context.c_str() << "...\"\n"; ERROR_LOG << "-------------------------\n"; } } int find_files(const char* filepath) { WIN32_FIND_DATA FindFileData; HANDLE hFind = INVALID_HANDLE_VALUE; DWORD dwError; char search_str[MAX_PATH_LEN] = {'\0'}; strncat(search_str, filepath, strlen(filepath)+1); strncat(search_str, "\\*", 3); hFind = FindFirstFile(search_str, &FindFileData); if (hFind == INVALID_HANDLE_VALUE) { printf ("Invalid file handle. Error is %u\n", GetLastError()); return (-1); } else { _recusive_dir(filepath, FindFileData); while (FindNextFile(hFind, &FindFileData) != 0) { _recusive_dir(filepath, FindFileData); } dwError = GetLastError(); FindClose(hFind); if (dwError != ERROR_NO_MORE_FILES) { printf ("FindNextFile error. Error is %u\n", dwError); return (-1); } } return (0); } void _recusive_dir(const char* filepath, const WIN32_FIND_DATA& FindFileData) { if ( FindFileData.dwFileAttributes != FILE_ATTRIBUTE_DIRECTORY ) { //match file char extname[64] = {'\0'}; char name[MAX_PATH_LEN] = {'\0'}; if(check_file_extension(FindFileData.cFileName, name, extname)) { if(strcmp(FindFileData.cFileName, "gc.material") == 0 || strcmp(FindFileData.cFileName, "gc.pu") == 0) return; char full_path[MAX_PATH_LEN] = {'\0'}; strncat(full_path, filepath, strlen(filepath)+1); strncat(full_path, "\\", 2); strncat(full_path, FindFileData.cFileName, strlen( FindFileData.cFileName)+1); //parse material file if (strcmp(extname, "material") == 0) parse_model_material(full_path); //parse pu file if(strcmp(extname, "pu") == 0) join_pu_files(full_path); } } else if(FindFileData.cFileName[0] != '.') { char full_path[MAX_PATH_LEN] = {'\0'}; strncat(full_path, filepath, strlen(filepath)+1); strncat(full_path, "\\", 2); strncat(full_path, FindFileData.cFileName, strlen( FindFileData.cFileName)); //recursive directory //printf ("Next file directory is %s\n", full_path); find_files(full_path); } return; } bool parser_config() { try { g_file_stream.open("art_material_script.cfg"); } catch (...) { std::cout << "缺少配置文件"<< std::endl; return false; } //获取文件内容 std::filebuf * pbuf = g_file_stream.rdbuf(); long size = pbuf->pubseekoff(0, std::ios::end, std::ios::in); pbuf->pubseekpos(0, std::ios::in); char* cbuf = new char[size]; memset(cbuf, '\0', size); pbuf->sgetn(cbuf, size); g_file_stream.close(); g_file_stream.clear(); std::string storage = cbuf; delete cbuf; typedef client::config::config_grammer<std::string::const_iterator> config_grammer_t; typedef client::config::comment_grammer<std::string::const_iterator> comment_grammer_t; config_grammer_t configset; client::config::session_list sessionlist; std::string::const_iterator iter = storage.begin(); std::string::const_iterator end = storage.end(); bool r = phrase_parse(iter, end, configset, comment_grammer_t(), sessionlist); if (r && iter == end) { client::config::session_list::iterator it_l = sessionlist.begin(); for (; it_l != sessionlist.end(); ++it_l) g_session_map.insert(std::make_pair(it_l->name, it_l->itemlist)); return true; } else { std::string::const_iterator some = iter+40; std::string context(iter, (some>end)?end:some); ERROR_LOG << "解析配置文件失败\n"; ERROR_LOG << "error occur at:\"" << (const char*)context.c_str() << "...\"\n"; return false; } return true; } void handle_material_files() { if(!parser_config()) return; g_file_stream.open("gc.material", std::ios_base::trunc | std::ios_base::out); g_file_stream << "\n"; g_file_stream.close(); g_file_stream.open("gc.pu", std::ios_base::trunc | std::ios_base::out); g_file_stream << "\n"; g_file_stream.close(); g_file_stream.clear(); char program_file_name[MAX_PATH_LEN] = {'\0'}; char program_path[MAX_PATH_LEN] = {'\0'}; GetModuleFileName(::GetModuleHandle(NULL), program_file_name, MAX_PATH_LEN); global_variant_init(); if(split_file_path(program_file_name, program_path)) { find_files(program_path); } mat_map::iterator it_g = g_mat_map.begin(); g_file_stream.open("gc.material", std::ios_base::app); for (;it_g != g_mat_map.end(); ++it_g) rewrite_material(it_g->second); g_file_stream.close(); return; } #endif