在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
开源软件名称:Effect-Designer开源软件地址:https://gitee.com/lzlong88/Effect-Designer开源软件介绍:Effect-Designer1.开源Effect-Designer的由来
2. 项目相关1.0 软件的由来和用途
2.0 工程的创建
3.部分代码预读解析1. 界面编辑功能的Undo和Redo功能1.0 工具的编辑功能支持对编辑操作等动作的Undo和Redo操作,首先这些动作不是具体的某种动作,是抽象的多类动作,所以笔者把这些动作抽象为动作基类ActionSlot,这个基类有两个抽象函数PerformUndoActionSlot()和PerformRedoActionSlot()来执行具体的Undo和Redo动作。2.0 其实实现Undo、Redo动作功能跟浏览器的后退和前进功能一样,主要是通过数据结构中的栈来实现的,即动作保持先进后出、后进先出,当有新的动作来到时即执行入栈操作;笔者这里是用一个双向链表来实现这个栈的,具体实现可以查看ActionSlotMgr类。2. 窗口的托盘图标安装类实现之前笔者在做REDM的时候封装过一个单例类,暴露出InstallIcon接口来达到接口调用的目的,后发现之前的单例类实现实在不美观,现在采用继承和模板类的思想来实现该类DMTrayIconImpl;任何窗口想实现托盘图标的安装继承该类即可,然后调用该父类的接口InstallIcon来实现托盘的安装操作。3. 资源包中json资源元素解析实现1.0 特效原始资源包中的json文件是整个资源元素结构的定义文件,里面定义了多种不同类型的元素类型,比如:backgroundEdge、beautifyParts、faceExchange、faceMorph(美妆父属性节点)、makeups(美妆节点)、parts(贴纸节点)、transitions等元素。程序需要根据这个json的定义来搭构界面元素和属性的设置。json文件格式大致定义如下:2.0 这些元素如何有规划的在界面搭建起来呢,笔者这里采用了DUI引擎读取XML文件的思想来巧妙的把这些元素转化成具体的类对象;如果熟悉DUI引擎的人都知道DUI引擎都是通过xml文件来保存界面元素信息的,比如一个Button类有着button的类属性和类方法,static类有static的类属性和类方法,然后这些类都是从DUIWindow父类继承下来的,这些子类重载了父类的部分虚函数。而这些子类的名称都会注册在类工厂里,xml里面只需要引用这些注册的类名(比如一个button对应注册的类名是“button”,xml里面写button即可构建一个按钮);当DUI引擎解析这个xml时,会从xml的顶节点开始递归的解析xml的所有节点,当遇到子控件(比如button)对象时,就会从类工厂里面寻找是否该类已经被注册,如果已经注册就会new出一个对应的类对象,然后把他放到控件树中,DUI通过维护这颗树的层级/父子关系来达到维护子控件的层级/父子关系。同样,笔者在解析json文件的时候也是用了这种思想:递归读取和解析json文件-->遇到子元素(如makeup节点)-->从类工厂查找对应的注册类,如果存在就new一个对应的对象-->将生成的对象指针加入到界面树结构中-->最后根据zposition熟悉微调界面元素的位置....。这些元素有个公共的父类EDJSonParser(类似DUI引擎中的DUIWindow基类),具体可参考工程Core目录下的代码。4. 类工厂注册模块类工厂模式是一个常用的设计模式,尤其在DUI引擎中对xml中的节点解析发挥了很大的作用,这点在上面的DUI加载xml的原理有过解释;REDM的类工厂的类注册就用的十分巧妙的,注册管理类DMRegMgr负责类的注册的;对应注册接口是:DMCode Register(IDMReg &RegObj, bool bReplace=false);参数中的IDMReg的实体子类实现其实是模板类template< class T> DMRegHelperT类,这个类的实现是极其巧妙的,因为他将真正的开辟的目标类对象(比如EDJSonParser类)用目标T来表示;该类本身的size大小为0,只有真正开辟目标类对象的时候才真正开辟内存空间。而这些注册到类工厂的目标类有个注册前提就是必须从EDBase类继承下来并且实现其三个静态函数:
所以每个从EDBase类继承的子类中都有类似EDDECLARE_CLASS_NAME(EDJSonParser,L"EDJSonParser", DMREG_Attribute) 的声明,EDDECLARE_CLASS_NAME其实就是这几个函数实现的宏定义。5. Event事件的绑定模块REDM很多模块其实写的非常不错的,其中一个就是DUI引擎中的Event函数的同步调用。Event管理类DMEventMgr用到了观察者模式所有注册进来的函数按EventID分类全部放一起,调用的时候根据EventID来进行函数的分发调用;而这些函数的调用是封装在以DMSlotFunctorBase为基类的DMFreeFunctionSlot(普通非类成员函数)类和DMMemberFunctionSlot(类成员函数)类中。DMMemberFunctionSlot类巧妙的利用了c++类模板来对不确定类注册的封装。最后类成员函数通过:
来完成类成员函数注册,普通函数是通过:
来完成普通函数注册。6.工程代码部分解析工程中最复杂的功能莫过于特效图片的编辑控件(DUIObjEditor)了,类中包含了DUIRoot(白色区域编辑区的顶层父窗口)成员以及DUIDragFrame(元素控件拖拽的顶层Trackrect)成员;所有图片元素控件都会创建在DUIRoot窗口下(子窗口),拖拽元素上层的DUIDragFrame窗口的时候会通过DUIPos修改对应编辑的图片控件的布局,图片控件的布局是描点布局;DUI库中需要重写描点布局Layout类,并将其重新注册来替换默认的DUI描点布局类。7. windows内存泄漏检测windows的内存泄漏检测经常采用一个开源库:“vld”来完成的。原理就是通过注册程序的内存开辟和释放的钩子来达到监控程序内存的开辟和释放,当有内存开辟时记录起来,当相应的内存释放时从记录中剔除,所以这个记录起来的表就是所有开辟未被释放的内存记录;然后通过这个记录记录的Eip可以回溯对应的开辟堆栈。笔者将vld核心代码提取并封装成CMemLeak,主要是考虑到:1.原生的vld代码和监测逻辑比较多,真正运行监测的时候会比较卡顿 2.原生的vld输出的内存开辟堆栈是零散的,笔者将同类的堆栈进行了归总和排序,也做了内存不同时间段的diff等小的封装来满足自己的需求。4. 工程编译与运行1.0 工程是通过cmake来维护的,需要提前安装cmake;工程支持底层用skia进行底层渲染,如果需要用到该功能,需要在cmake过程中勾选相应的选项来支持。2.0 工程debug的时候会通过相对目录来定位程序的DUI资源,DUI的xml等相关界面资源目录在EDesigner\Res\EDesignerRes目录下,Debug模式下采用相对目录读取资源文件的方式;但是在Release模式下需要把资源目录下的layout和themes文件夹压缩为EDesignerRes.zip并放在Res目录下;Release模式下会把DUI压缩资源链接到Exe文件的资源段里,这样虽然增大了Exe的体积,但可以避免将界面资源文件直接暴露给用户,也可以避免升级不完全或者用户修改而导致界面资源文件不完整而引起的Bug。5. 开源协议Effect-Designer需要遵守什么开源协议?
6. 关于
|
请发表评论