ssRender Plugin 基础
一.什么是Plugin
插件(Plug-in,又称addin、add-in、addon或add-on,又译外挂)是一种遵循一定规范的应用程序接口编写出来的程序。其只能运行在程序规定的系统平台下(可能同时支持多个平台),而不能脱离指定的平台单独运行。因为插件需要调用原纯净系统提供的函数库或者数据。很多软件都有插件,插件有无数种。例如在IE中,安装相关的插件后,WEB浏览器能够直接调用插件程序,用于处理特定类型的文件。
插件是一种可以添加到现有软件中的程序,它可以改善或更改软件的功能,而无需更改现有软件的源代码。插件是一种可以添加到软件中的组件,它可以改变或增强软件的功能,从而提高软件的性能和可用性。插件可以是第三方软件,也可以是由软件开发者自行开发的软件。
通常是用于对某个现有的架构进行扩展。
二. ssRender Plugin
顾名思义,就是用于ssRender的插件,是ssRender工具端的扩展应用,用户可以根据需求(自定义OpenGL效果、作为通信终端为ssRender工具端提供数据等),进行自定义设计,然后在ssRender工具端加载并应用。
ssRender Plugin可以实现的功能:
- 自定义渲染效果:开发人员可以在Plugin插件程序中自定义OpenGL效果,然后加载到ssRender工具端进行预览和调试。
- 自定义属性:在Plugin插件程序中可以创建自定义属性值,在ssRender工具端加载插件后,可以在属性栏中修改对应的属性参数,并在ssRender工具端的Preview预览界面中查看Plugin插件实现的效果。
- 自定义信号:在Plugin插件程序中,定义与ssRender工具端交互的Event信号,在ssRender工具端加载插件后,可以在属性栏中查看,在ssRender工具端的Event 编辑器中进行表达式绑定,信号最终由Plugin插件程序主动触发。
实现对ssRender工具端的功能扩展,丰富了开发人员对于ssRender工具端的使用方式和设计方式,满足了开发人员以及产品的个性定制化需求。
三.ssRender Plugin Demo
下面用vs2015创建一个ssRender Plugin工程
1.创建动态链接库工程
2.修改工程属性,改为DLL
3.配置include和lib
①include配置
include\glm
include\freetype
include\ssRender
include\win_include
include\ssRender\plugin
include\ssRender\effects
include\ssRender\graphicItems
这些文件是ssRender工程中的include,直接include就行
②lib配置
ssRender工程中的lib也如下图这样包一下
还需要添加如下依赖库:
jpeg.lib
glfw3.lib
ssrCore.lib
freetype.lib
libpng16.lib
ssrPlugin.lib
pthreadVC2.lib
4.添加预编译宏定义
5.添加源文件
①添加PluginTest.h头文件
PluginTest.h
#pragma once
#include"PluginBase.h"
#ifdef _PLUGIN_TYPE_RENDER_
class UserPluginDLL : public PluginBase, public Item
#else
class UserPluginDLL : public PluginBase
#endif
{
public:
UserPluginDLL();
~UserPluginDLL();
//实例化SSR对象
SSRObject* createSSRObject();
//删除plugin实例化
void deleteSSRObject(SSRObject* ssrObject);
//更新数据
int upDateData(SSRObject* ssrObject);
#ifdef _PLUGIN_TYPE_RENDER_ //该宏定义是为了区分数据类型的plugin和渲染类型的plugin
SSR_PLUGIN_DECLARATION(DataSource, PLUGIN_RENDER, "Author:**", "2022/**/**") //定义作者
#else
SSR_PLUGIN_DECLARATION(UserPluginDLL, PLUGIN_DATA, "Author:zhanghao", "2023/03/14")
#endif
SSR_PLUGIN_PROPERTY_DEF_BEGIN(UserPluginDLL) //定义属性开始
SSR_PLUGIN_PLUGIN_PROPERTY("DataSource", "MoveX",TYPE_INT,"0",0,600,"PROPTY_TIPS")
SSR_PLUGIN_PLUGIN_PROPERTY("DataSource", "MoveY",TYPE_INT,"0",0,600,"PROPTY_TIPS")
//可以多次调用SSR_PLUGIN_PLUGIN_PROPERTY()创建不同的属性
SSR_PLUGIN_PROPERTY_DEF_END() //定义属性结束
SSR_PLUGIN_EVENT_DEF(UserPluginDLL) //定义事件开始
SSR_PLUGIN_EVENT("CustomEventId")
//可以多次调用SSR_PLUGIN_EVENT()创建不同的自定义EventId
SSR_PLUGIN_EVENT_DEF_END()//定义事件结束
int m_runningFlg;
pthread_t Key_thread;
int MoveX = 0;
int MoveY = 0;
};
②添加PluginTest.cpp源文件
PluginTest.cpp
//#ifndef _PLUGIN_TYPE_RENDER_
//#define _PLUGIN_TYPE_RENDER_
//#endif
#include"PluginTest.h"
#include<sstream>
#include <math.h>
void* keyStatus(void* arg);
UserPluginDLL::UserPluginDLL()
{
m_runningFlg = false;
}
UserPluginDLL::~UserPluginDLL()
{
m_runningFlg = false;
}
SSRObject* UserPluginDLL::createSSRObject()
{
#ifdef _PLUGIN_TYPE_RENDER_
SSRObject* ssrObj = new Item;
#else
SSRObject* ssrObj = new SSRObject;
#endif
ssrObj->m_ssRptr_plugin = this;
ssrObj->m_ssRtype = OBJECT_TYPE_PLUGIN;
m_runningFlg = true;
pthread_create(&Key_thread, NULL, keyStatus, (void *)ssrObj);
//Common::printlog(LOG_LEV_ERROR, "zzzzzzzzzcreateSSRObjectzzzzzzzz");
return ssrObj;
}
void UserPluginDLL::deleteSSRObject(SSRObject* ssrObject)
{
if (ssrObject)
{
m_runningFlg = false;
Common::sleep(150);
delete ssrObject;
ssrObject = NULL;
}
}
SSR_PLUGIN_DEFINITION(UserPluginDLL)//调用此宏定义,创建预定义函数接口
int UserPluginDLL::upDateData(SSRObject* ssrObject)
{
ProptyList::iterator it = UserPluginDLL::m_listPropties.begin();
for (; it != UserPluginDLL::m_listPropties.end(); it++)
{
Property prop((*it));
if (prop.name == "MoveX")
{
prop.value = Common::int2str(MoveX);
}
else if (prop.name == "MoveY")
{
prop.value = Common::int2str(MoveY);
}
if (m_renderEngine)
{
m_renderEngine->getPropertySystem()->setPropertyValue(ssrObject, prop.name, prop.value);
}
}
return 0;
}
void* keyStatus(void* arg)
{
SSRObject* ssrObject = (SSRObject*)arg;
UserPluginDLL* dataSource = (UserPluginDLL*)ssrObject->m_ssRptr_plugin;
if (dataSource)
{
int X = 0, Y = 0;
while (dataSource->isRunning() && dataSource->m_runningFlg)
{
//Common::printlog(LOG_LEV_ERROR, "zzzzzzzzzkeyStatustzzzzzzzz");
if (X > 0 && X < 300 && Y == 0)
{
X += 1;
Y = 0;
}
else if (X == 300 && Y == 0)
{
X -= 1;
Y += 1;
}
else if (X > 150 && X < 300 && Y < 150)
{
X -= 1;
Y += 1;
}
else if (X == 150 && Y == 150)
{
X -= 1;
Y -= 1;
}
else if (X > 0 && X < 150 && Y < 150)
{
X -= 1;
Y -= 1;
}
else if (X == 0 && Y == 0)
{
X += 1;
Y = 0;
}
dataSource->MoveX = X;
dataSource->MoveY = Y;
dataSource->upDateData(ssrObject);
Common::sleep(10);
}
}
return 0;
}
6.编译工程
ssRenderPluginTest.dll就是我们编译完生成的插件了。
四.Plugin导入到ssRender
1.打开ssRender,新建一个工程
2.添加ssRenderPlginTest工程生成的插件
3.加载Plugin
将添加的ssRenderPluginTest插件拖拽到Page上即可,右边就会显示Plugin的属性。
五.ssRender Plugin 接口定义
1. SSR_PLUGIN_DEFINITION
①声明
SSR_PLUGIN_DEFINITION(DERIVED_CLASS)
②描述
用于定义自定义Plugin插件。
③参数
Name | Data type | Description |
---|---|---|
DERIVED_CLASS | 类名 | 继承于PluginBase类 |
④示例
PluginTest.cpp:
UserPluginDLL:: UserPluginDLL ()
{
}
UserPluginDLL::~ UserPluginDLL ()
{
}
SSR_PLUGIN_DEFINITION(UserPluginDLL)
2. SSR_PLUGIN_DECLARATION
①声明
SSR_PLUGIN_DECLARATION(DERIVED_CLASS, PLUGIN_TYPE,PLUGIN_AUTHOR,CREATE_DATE)
②描述
用于声明自定义Plugin插件的信息。
③参数
Name | Data type | Description |
---|---|---|
DERIVED_CLASS | 类名 | 继承于PluginBase类 |
PLUGIN_TYPE | 枚举类型 | 定义Plugin插件的类型: PLUGIN_DATA, 定义插件为数据类型; PLUGIN_RENDER,定义插件为渲染类型。 |
PLUGIN_AUTHOR | 字符串类型 | Plugin插件的作者名字 例:“AuthorXX” |
CREATE_DATE | 字符串类型 | Plugin插件的创建时间 例:“20XX/XX/XX” |
④示例
PluginTest.h:
class UserPluginDLL : public PluginBase {
SSR_PLUGIN_DECLARATION(UserPluginDLL, PLUGIN_DATA, "XX","2022/XX/XX")
}
3. SSR_PLUGIN_PROPERTY_DEF_BEGIN
①声明
SSR_PLUGIN_PROPERTY_DEF_BEGIN(DERIVED_CLASS)
②描述
用于声明Plugin插件的自定义属性的开始。
③参数
Name | Data type | Description |
---|---|---|
DERIVED_CLASS | 类名 | 继承于PluginBase类 |
④示例
PluginTest.h:
class UserPluginDLL : public PluginBase {
SSR_PLUGIN_PROPERTY_DEF_BEGIN(UserPluginDLL)
SSR_PLUGIN_PLUGIN_PROPERTY("group_name", "property_name1", TYPE_INT, "1", 0, 100,
"This is a custom property node!")
SSR_PLUGIN_PLUGIN_PROPERTY("group_name", "property_name2", TYPE_INT, "1", 0, 100,
"This is a custom property node!")
SSR_PLUGIN_PROPERTY_DEF_END()
}
4. SSR_PLUGIN_PLUGIN_PROPERTY
①声明
SSR_PLUGIN_PLUGIN_PROPERTY(GROUP_NAME_TYPE_STR,
PROPTY_NAME_TYPE_STR,
PROPTY_VALUE_TYPE_ENUM,
PROPTY_VALUE_TYPE_STR,
PROPTY_VALUE_MIN_TYPE_NUM,
PROPTY_VALUE_MAX_TYPE_NUM,
PROPTY_TIPS_TYPE_STR)
②描述
用于声明Plugin插件的自定义属性。
③参数
Name | Data type | Description |
---|---|---|
GROUP_NAME_TYPE_STR字符串类型 | 字符串类型 | 属性分组的组名 |
PROPTY_NAME_TYPE_STR | 字符串类型 | 属性节点的名字 |
PROPTY_VALUE_TYPE_ENUM | 枚举类型 | 属性节点的值类型: TYPE_BOOL, 布尔类型; TYPE_FLOAT, 单精度浮点类型; TYPE_INT, 整数类型; TYPE_SHORT, 短整形 TYPE_UNSIGED_SHORT, 无符号短整形 TYPE_STRING, 字符类型; |
PROPTY_VALUE_TYPE_STR | 字符串类型 | 属性节点的值 |
PROPTY_VALUE_MIN_TYPE_NUM | int类型 | 属性节点的最小值 |
PROPTY_VALUE_MAX_TYPE_NUM | int类型 | 属性节点的最大值 |
PROPTY_TIPS_TYPE_STR | 字符串类型 | 属性节点的描述注释 |
④示例
同SSR_PLUGIN_PROPERTY_DEF_BEGIN。
5. SSR_PLUGIN_PROPERTY_DEF_END
①声明
SSR_PLUGIN_PROPERTY_DEF_END()
②描述
用于声明Plugin插件的自定义属性的结束,跟SSR_PLUGIN_PROPERTY_DEF_BEGIN成对出现。
③参数
无。
④示例
同SSR_PLUGIN_PROPERTY_DEF_BEGIN。
6.SSR_PLUGIN_EVENT_DEF
①声明
SSR_PLUGIN_EVENT_DEF(DERIVED_CLASS)
②描述
用于声明Plugin插件的自定义信号的开始。
③参数
Name | Data type | Description |
---|---|---|
DERIVED_CLASS | 类名 | 继承于PluginBase类 |
④示例
PluginTest.h:
class UserPluginDLL : public PluginBase {
SSR_PLUGIN_EVENT_DEF(UserPluginDLL)
SSR_PLUGIN_EVENT("custom_event1")
SSR_PLUGIN_EVENT("custom_event2")
SSR_PLUGIN_EVENT_END()
}
7. SSR_PLUGIN_EVENT
①声明
SSR_PLUGIN_EVENT(EVENT)
②描述
用于声明Plugin插件的自定义信号。
③参数
Name | Data type | Description |
---|---|---|
EVENT | 字符串类型 | 信号的名字,不可以用特殊字符或者空格 |
④示例
同SSR_PLUGIN_EVENT_DEF。
8. SSR_PLUGIN_EVENT_END
①声明
SSR_PLUGIN_EVENT_END()
②描述
用于声明Plugin插件的自定义信号的结束,跟SSR_PLUGIN_EVENT_DEF成对出现。
③示例
同SSR_PLUGIN_EVENT_DEF。
9.默认需要定义的接口
Plugin源文件中需要默认声明三个接口函数,ssRender引擎会按照程序执行状态自动调用。需要注意的是这三个接口必须声明。
(1)createSSRObject
①声明
SSRObject* createSSRObject()
②描述
此函数会在ssRender工具端创建Plugin节点的时候自动调用,需要在此时添加的自定义内容,可写在此函数当中。
③示例
PluginTest.cpp:
void UserPluginDLL::createSSRObject()
{
#ifdef _PLUGIN_TYPE_RENDER_
SSRObject* ssrObj = new UserPluginDLL;
#else
SSRObject* ssrObj = new SSRObject;
#endif
ssrObj->m_ssRptr_plugin = this;
ssrObj->m_ssRtype = OBJECT_TYPE_PLUGIN;
//以上的代码部分除了渲染类型分支的new类名需要修改之外,其他代码变更,拷贝即可
//此处可以加其他自定义业务逻辑内容
return ssrObj;
}
(2)deleteSSRObject
①声明
void DERIVED_CLASS::deleteSSRObject(SSRObject* ssrObject)
②描述
此函数会在ssRender工具端删除Plugin节点,并释放资源的时候自动调用,需要在此时添加的自定义内容,可写在此函数当中。
③参数
Name | Data type | Description |
---|---|---|
SSRObject*ssrObject | SSRObject类型指针 | 表示当前plugin的对象 |
③示例
PluginTest.cpp:
UserPluginDLL.cpp:
void UserPluginDLL:: deleteSSRObject (SSRObject* ssrObject)
{
if (ssrObject)
{
delete ssrObject;
ssrObject = NULL;
}
//以上的代码部分无需变更,拷贝即可
//此处可以加其他自定义业务逻辑内容
}
(3)createUI
①声明
void DERIVED_CLASS:: createUI(SSRObject* ssrObject)
②描述
此函数会在ssRender工具端创建Plugin节点的时候自动调用,时序在createSSRObject 之后,需要在此时添加的自定义渲染内容,可写在此函数当中。
③参数
Name | Data type | Description |
---|---|---|
SSRObject*ssrObject | SSRObject类型指针 | 表示当前plugin的对象 |
③示例
void UserPluginDLL::createUI(SSRObject* ssrObject)
{
//创建一个根节点Root把createSSRObject()中的m_ssrObject传给Root
Item* Root = (Item*) ssrObject;
if (Root)
{
//创建一个ColorBlock(继承Item类)对象m_Color
ColorBlock* m_Color = new ColorBlock;
m_Color->initialize();//初始化节点
m_Color->setColor(glm::vec4(1.0, 0.8, 0.1, 1.0));//设置颜色
Root->addChild(m_Color);//把m_Color节点挂在Root节点下才可显示
}
}
注意:如果想在此函数内自定义渲染内容,要把自定义的节点挂在当前的plugin节点下面才可显示 ,上述代码示例可参考。
10.自定义信号的触发
①声明
EventSystem::create()->onEvent(this, "EventName")
②描述
调用此函数触发Plugin插件的自定义信号,ssRender工具端,会受到对应的信号,插件类型为渲染类型时才可使用。
③参数
Name | Data type | Description |
---|---|---|
this | this指针 | 继承PluginBase的派生类的this指针 |
EventName | 字符串类型 | 利用SSR_PLUGIN_EVENT接口定义的信号 |
④例子
void UserPluginDLL::update()
{
EventSystem::create()->onEvent(this,"custom_event1");
}
11.日志打印
①声明
Common::printlog(LOG_LEV, “”,…)
②描述
此函数要引用"common.h"文件,会根据设定的log等级和分类,打印指定级别的log,用法同常规的printf打印函数。
③参数
Name | Data type | Description |
---|---|---|
LOG_LEV | 枚举类型 | LOG_LEV_ERROR 错误等级日志 LOG_LEV_INFORMATION 信息日志 LOG_LEV_DEBUG 调试日志 LOG_LEV_COREDUMP 内核错误日志 |
④示例
void UserPluginDLL::update()
{
EventSystem::create()->onEvent(this,"custom_event1");
}
12.插件工作状态的判断
①描述
通过isRunning接口判定当前插件的工作状态,工作中返回true,否则返回false。
②示例
void UserPluginDLL::createSSRObject()
{
#ifdef _PLUGIN_TYPE_RENDER_
SSRObject* ssrObj = new UserPluginDLL;
#else
SSRObject* ssrObj = new SSRObject;
#endif
ssrObj->m_ssRptr_plugin = this;
ssrObj->m_ssRtype = OBJECT_TYPE_PLUGIN;
//以上的代码部分除了渲染类型分支的new类名需要修改之外,其他代码变更,拷贝即可
//此处可以加其他自定义业务逻辑内容
pthread_create(&m_thread, NULL, work_thread, (void *)this);
m_runningFlg = true;
return ssrObj;
}
void work_thread(void* arg)
{
SSRObject* ssrObject = (SSRObject*)arg;
UserPluginDLL* dataSource = (UserPluginDLL*)ssrObject->m_ssRptr_plugin;
//UserPluginDll继承于PluginBase
if (dataSource->isRunning() && dataSource->m_runningFlg)
{
...//通过isRunning接口判定当前插件的工作状态,返回值为true/false
};
}
void UserPluginDLL:: deleteSSRObject (SSRObject* ssrObject)
{
//注意:删除plugin时要把启动的线程标志置成false以免发生异常
if (ssrObject)
{
m_runningFlg=false;
Common::sleep(150);
delete ssrObject;
ssrObject = NULL;
}
}
六.ssRender Plugin插件编码范例
UserPluginDLL头文件(.h),需要引入头文件PluginBase.h:
#pragma once
#include "PluginBase.h"
#ifdef _PLUGIN_TYPE_RENDER_ //该宏定义是为了区分数据类型的plugin和渲染类型的plugin
class UserPluginDLL : public PluginBase, public Item
#else
class UserPluginDLL : public PluginBase
#endif
{
public:
UserPluginDLL();
~UserPluginDLL();
//实例化SSR对象
SSRObject* createSSRObject();
//实例化之后停止stop
void deleteSSRObject(SSRObject* ssrObject);
#ifdef _PLUGIN_TYPE_RENDER_ //该宏定义是为了区分数据类型的plugin和渲染类型的plugin
void loadMyShader();
virtual void updateMyVar();
SSR_PLUGIN_DECLARATION(UserPluginDLL, PLUGIN_RENDER,"Author:**","2022/**/**")
#else
SSR_PLUGIN_DECLARATION(UserPluginDLL,PLUGIN_DATA,"Author:**","2022/**/**")
#endif
SSR_PLUGIN_PROPERTY_DEF_BEGIN(UserPluginDLL) SSR_PLUGIN_PLUGIN_PROPERTY("GROUP_NAME","PROPTY_NMAE",
TYPE_INT,"1",1,100,"PROPTY_TIPS")
//可以多次调用SSR_PLUGIN_PLUGIN_PROPERTY,创建不同的属性。
SSR_PLUGIN_PROPERTY_DEF_END()
SSR_PLUGIN_EVENT_DEF(UserPluginDLL)
SSR_PLUGIN_EVENT("CustomEventId")
//可以多次调用SSR_PLUGIN_EVENT()创建不同的自定义EventId
SSR_PLUGIN_EVENT_DEF_END()
};
UserPluginDLL源文件(.cpp):
#ifndef _PLUGIN_TYPE_RENDER_
#define _PLUGIN_TYPE_RENDER_//该宏定义是为了区分数据类型的plugin和渲染类型的plugin
#endif
#include "UserPluginDLL.h"
UserPluginDLL::UserPluginDLL()
{
#ifdef _PLUGIN_TYPE_RENDER_
loadMyShader();
#endif
}
UserPluginDLL::~UserPluginDLL()
{
}
SSRObject* UserPluginDLL::createSSRObject()
{
#ifdef _PLUGIN_TYPE_RENDER_//该宏定义是为了区分数据类型的plugin和渲染类型的plugin
SSRObject* ssrObj = new UserPluginDLL;
ssrObj->m_ssRptr_plugin = this;
#else
SSRObject* ssrObj = new SSRObject;
ssrObj->m_ssRptr_plugin = this;
#endif
ssrObj->m_ssRtype = OBJECT_TYPE_PLUGIN;
return ssrObj;
}
void UserPluginDLL::deleteSSRObject(SSRObject* ssrObject)
{
if (ssrObject)
{
delete ssrObject;
ssrObject = NULL;
}
}
SSR_PLUGIN_DEFINITION(UserPluginDLL)//调用此宏定义,创建预定义函数接口
#ifdef _PLUGIN_TYPE_RENDER_
//自定义Shader :
//Vertex Shader
char vShaderStr_my[] =
"attribute vec3 ssVertexPosition; \n" //【不可修改】变量名固定
"attribute vec2 ssVertexUV; \n" //【不可修改】变量名固定
"uniform mat4 ssMVP; \n" //【不可修改】变量名固定
"varying vec2 ssUV; \n" //【不可修改】变量名固定
"void main() \n"
"{ \n"
"gl_Position = ssMVP*vec4(ssVertexPosition, 1.0); \n"
"ssUV = ssVertexUV; \n"
"}\n";
//Fragment Shader
char fShaderStr_my[] =
"precision mediump float; \n"
"varying vec2 ssUV; \n"
"uniform sampler2D ssTextureSampler; \n" //【不可修改】变量名固定
"uniform vec3 myColor; \n" //【自定义】变量
"void main() \n"
"{\n"
"gl_FragColor = texture2D(ssTextureSampler, ssUV)+vec4(myColor, 0.1);\n"
"}\n";
void UserPluginDLL::loadMyShader()
{
//需要定义Program名字
setMyShaderSource("Custom_MyItem", vShaderStr_my, fShaderStr_my);
}
void UserPluginDLL::updateMyVar()
{
//修改自定义变量的值
setVec3("myColor", 1.0, 0.0, 0.0);
}
#endif