战魂小筑

讨论群:309800774 知乎关注:http://zhihu.com/people/sunicdavy 开源项目:https://github.com/davyxu

   :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理 ::
  252 随笔 :: 0 文章 :: 506 评论 :: 0 Trackbacks
 

最近在写D3D9模拟D3D10接口的渲染系统中碰到大量的渲染状态对象,不仅成员多,枚举也多的要命。

 

    struct CORE_API RasterizerState : ResourceHandle            
    {
        eFillMode            mFillMode;        
        eCullMode            mCullMode;
        bool                mFrontFaceCCW;
        float                mDepthBias;
        float                mSlopeScaledDepthBias;
        bool                mDepthClipEnable;
        bool                mScissorEnable;
        bool                mMultisampleEnable;

        RasterizerState();
    };

而要从配置文件中读取数据并填充到这个结构体,对于C++来说完全就是吃力不讨好的,写出来的代码也是极为过程,修改和扩展极为麻烦的。

因此决定使用反射的方法来填充数据,先总结一下我的C++反射系统

class RTTIObject // 动态类型识别对象基类,对象通过一些宏后可以很方便的通过字符串创建出类实例,并且可以查询注册时的类型和其他绑定信息
class NameRef  // 名字表,类似于虚幻中的FName,可以定义Const和普通Name,比较和拷贝只是一个dword耗费的时间
value_parse,value_tostring,value_typename // 一系列类型模板函数,提供对类型的ToString,Parse及类型名查询

 

首先需要处理的是枚举查询,这里将枚举通过宏做成一个个枚举对象,并可以通过名字创建实例

#define DECLARE_ENUMOBJECT( TEnum ) \
    struct EnumObject_##TEnum : EnumObject\
    {\
    DECLARE_RTTIOBJECT( EnumObject_##TEnum );\
    EnumObject_##TEnum( );\
    };


#define IMPLEMENT_ENUMOBJECT_BEGIN( TEnum, TEnum_prefixoffset, TMember_prefixoffset ) \
    IMPLEMENT_RTTIOBJECT_STRING( EnumObject_##TEnum, #TEnum + TEnum_prefixoffset, #TEnum + TEnum_prefixoffset, "EnumObject" )\
    EnumObject_##TEnum::EnumObject_##TEnum(){ const int member_prefixoffset = TMember_prefixoffset;

#define ENUMOBJECT_ADD( enumkey ) AddMember( #enumkey + member_prefixoffset, (dword)enumkey );

#define IMPLEMENT_ENUMOBJECT_END }

#define ENUMOBJECT_STATICINIT( TEnum ) EnumObject_##TEnum::StaticInit();

EnumObject 中通过宏将枚举的名称和值保存在这个对象中

IMPLEMENT_ENUMOBJECT_BEGIN( eFillMode, 1, 3 )  // 这里的1,3是将eFillMode及FM_Point转成字符串后去掉前缀
    ENUMOBJECT_ADD( FM_Point )
    ENUMOBJECT_ADD( FM_Line )
    ENUMOBJECT_ADD( FM_Fill )
IMPLEMENT_ENUMOBJECT_END

// 注册到RTTIObject系统

ENUMOBJECT_STATICINIT( eFillMode )

 

// 通过枚举对象可以查找到字符串对应的值
dword v;
EnumObject::GetEnumValue( "FillMode", "Point", v )



下一步是将结构体成员信息记录

    void SettingObject::BindMember( const NameRef& objname, void* instancePtr, void* dataPtr, SettingProxy* proxy )
    {
        proxy->mOffset = dword(dataPtr) - dword(instancePtr);

        MemberList& memberlist = mSettingMap[ objname ];
        memberlist[ proxy->mName ] = proxy;
    }

这里记录的是结构体成员的内存偏移

使用大量的宏,可以让结构体绑定变得漂亮

#define BIND_SETTINGOBJECT_BEGIN( TClass ) \
    { const NameRef& soname = TClass::StaticGetClassInfo()->mClassName;TClass soobj;

#define BIND_SO_MEMBER( TMemberType, TMember ) \
    so.BindMember( soname, &soobj, &soobj.TMember, new TSettingElement<TMemberType>(#TMember + 1 ) );

#define BIND_SO_MEMBER_NAME( TMemberType, TMember, TName ) \
    so.BindMember( soname, &soobj, &soobj.TMember, new TSettingElement<TMemberType>(TName) );

#define BIND_SO_ENUM( TEnumType, TMember ) \
    so.BindMember( soname, &soobj, &soobj.TMember, new TSettingEnum(#TMember + 1, #TEnumType + 1) );

#define BIND_SO_ENUM_NAME( TEnumType, TMember, TName ) \
    so.BindMember( soname, &soobj, &soobj.TMember, new TSettingEnum(TName, #TEnumType + 1) );

#define BIND_SETTINGOBJECT_END }

绑定代码如下

        BIND_SETTINGOBJECT_BEGIN( RasterizerState )
            BIND_SO_ENUM    ( eFillMode    , mFillMode )
            BIND_SO_ENUM    ( eCullMode    , mCullMode )
            BIND_SO_MEMBER    ( bool        , mFrontFaceCCW )
            BIND_SO_MEMBER    ( float        , mDepthBias )
            BIND_SO_MEMBER    ( float        , mSlopeScaledDepthBias)
            BIND_SO_MEMBER    ( bool        , mDepthClipEnable)
            BIND_SO_MEMBER    ( bool        , mScissorEnable)
            BIND_SO_MEMBER    ( bool        , mMultisampleEnable)
        BIND_SETTINGOBJECT_END

 

所有结构体的信息被记录在SettingObject中,读取配置文件填充结构体的任务就变得异常的简单了

    SettingObject settings;
// 将所有的结构体信息记录
    InitRenderStateObjectSetting( settings );

    const NameRef& rzname = DepthStencilState::StaticGetClassInfo()->mClassName;

    DepthStencilState a;
 // 这里就是将配置文件的信息填充到结构体
    settings.SetMember( rzname, &a, "BackFace.StencilFunc", "Equal" );
 
posted on 2010-02-26 17:58 战魂小筑 阅读(2267) 评论(0)  编辑 收藏 引用 所属分类: 游戏开发技术C++/ 编程语言渲染 Shader 引擎

只有注册用户登录后才能发表评论。
【推荐】超50万行VC++源码: 大型组态工控、电力仿真CAD与GIS源码库
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理