饭后温柔

汉堡与老干妈同嚼 有可乐味
  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

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

Posted on 2012-09-01 13:25  饭后温柔  阅读(1027)  评论(0编辑  收藏  举报

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