• 使用boost spirit库解析ogre材质脚本


    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

      

  • 相关阅读:
    Maven属性
    安居客Android项目架构演进
    HttpClient 解说 (1) 基础
    linux 打包和压缩文件
    java AES-256加解密解决方法
    jdk8 分隔字符串最新方法
    springboot 过滤器,拦截器,切片的运用
    thinkphp 5.0手记
    如何使用UDP进行跨网段广播
    php multicast多播实现详解
  • 原文地址:https://www.cnblogs.com/flytrace/p/2666543.html
Copyright © 2020-2023  润新知