ssRender Plugin 基础

news2024/10/1 1:29:19

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插件。

③参数

NameData typeDescription
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插件的信息。

③参数

NameData typeDescription
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插件的自定义属性的开始。

③参数

NameData typeDescription
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插件的自定义属性。

③参数

NameData typeDescription
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_NUMint类型属性节点的最小值
PROPTY_VALUE_MAX_TYPE_NUMint类型属性节点的最大值
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插件的自定义信号的开始。

③参数

NameData typeDescription
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插件的自定义信号。

③参数

NameData typeDescription
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节点,并释放资源的时候自动调用,需要在此时添加的自定义内容,可写在此函数当中。

③参数
NameData typeDescription
SSRObject*ssrObjectSSRObject类型指针表示当前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 之后,需要在此时添加的自定义渲染内容,可写在此函数当中。

③参数
NameData typeDescription
SSRObject*ssrObjectSSRObject类型指针表示当前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工具端,会受到对应的信号,插件类型为渲染类型时才可使用。

③参数

NameData typeDescription
thisthis指针继承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打印函数。

③参数

NameData typeDescription
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 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/545111.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Windows安装配置Tomcat服务器教程 -- 外网远程访问

文章目录 前言1.本地Tomcat网页搭建1.1 Tomcat安装1.2 配置环境变量1.3 环境配置1.4 Tomcat运行测试1.5 Cpolar安装和注册 2.本地网页发布2.1.Cpolar云端设置2.2 Cpolar本地设置 3.公网访问测试4.结语 转载自cpolar文章&#xff1a;外网访问本地Tomcat服务器【cpolar内网穿透】…

【SpringBoot】五:Web服务---SpringMVC---控制器

文章目录 1 控制器介绍2 控制器工作流程3 控制器中的方法4 匹配请求路径到控制器方法5 RequestMapping6 控制器方法参数类型与可用返回值类型7 接收请求参数8 验证参数8.1 Bean Validation8.2 分组校验8.3 ValidationAutoConfiguration 1 控制器介绍 &#xff08;1&#xff09…

【Linux Network】数据链路层

目录 认识以太网 以太网帧格式 认识MAC地址 对比理解MAC地址和IP地址 认识MTU MTU对IP协议的影响 MTU对UDP协议的影响 MTU对于TCP协议的影响 MSS和MTU的关系&#xff1a; 查看硬件地址和MTU ARP协议 ARP协议的作用 ARP协议的工作流程 ARP数据报的格式 DNS(Domain Name System) …

近期要做填报报表,使用Spreadsheet还是Finereport?

又是忙碌的五月呀~~近期接到一个项目&#xff0c;是一家商贸公司需要去采集销售部门的销售业绩据&#xff0c; 以往他们使用Excel表格线下去做报表填报&#xff0c;传统的报表体系效率低&#xff0c;文件杂&#xff0c;汇总难。下级部门上传数据需要以多个表格来上报&#xff0…

Python3安装

依赖安装 gcc是一个用于linux系统下编程的编译器&#xff0c;由于python3需要编译安装&#xff0c;因此&#xff0c;需要首先安装gcc。先查看一下系统中&#xff0c;是否安装了gcc。 gcc --versions 发现没有安装&#xff0c;则需要安装。参数-y的作用是在安装过程中自动确认…

在 Python 中制作偶数列表

文章目录 开始什么是偶数在 Python 中使用 for 循环创建偶数列表在 Python 中使用 while 循环制作偶数列表使用列表理解在 Python 中制作偶数列表使用 Lambda 表达式在 Python 中创建偶数列表 开始 我们将通过示例介绍偶数列表以及在 Python 中创建偶数列表的不同方法。 什么是…

今天公司来了个拿 30K 出来的测试,算是见识到了基础的天花板

今天上班开早会就是新人见面仪式&#xff0c;听说来了个很厉害的大佬&#xff0c;年纪还不大&#xff0c;是上家公司离职过来的&#xff0c;薪资已经达到中高等水平&#xff0c;很多人都好奇不已&#xff0c;能拿到这个薪资应该人不简单&#xff0c;果然&#xff0c;自我介绍的…

韩国访问学者签证D-2-5材料准备及签证流程

韩国的签证种类很多&#xff0c;对于申请访问学者签证来说&#xff0c;较常见的签证种类是D-2-5签证和E-3签证&#xff0c;本篇知识人网小编先介绍D-2-5签证。 签证的材料准备 根据韩国大使馆2023年4月12日最新发布的“签证申请与准备材料指导”内容, D-2-5签证的签发对象及准…

一文带你了解电信终端指南(详细篇)

​ 电信入库认证周期&#xff1a; 常规为 4-6 周&#xff0c;我公司可加急完成认证&#xff0c;请拨打免费服务热线 400 626 0709 或联系 蒋先生 13823213584&#xff08;微信同号&#xff09;了解详情。 中国电信集团公司是我国特大型国有通信企业、上海世博会全球合作伙伴&a…

Yolov5轻量化:EMO,结合 CNN 和 Transformer 的现代倒残差移动模块设计,性能优于EdgeViT、Mobile-former等网络

论文: https://arxiv.org/pdf/2301.01146.pdf 🏆🏆🏆🏆🏆🏆Yolo轻量化模型🏆🏆🏆🏆🏆🏆 重新思考了 MobileNetv2 中高效的倒残差模块 Inverted Residual Block 和 ViT 中的有效 Transformer 的本质统一,归纳抽象了 MetaMobile Block 的一般概念。受这…

深度学习4 -- 卷积神经网络(代码实现篇+付详细流程文件)

引言 本文是使用pytorch对卷积神经网络(Convolutional Neural Network, CNN)的代码实现&#xff0c;作为之前介绍CNN原理的一个代码补充。本文代码相关介绍相对较为详细&#xff0c;也为自己的一个学习过程&#xff0c;有错误的地方欢迎指正。本人介绍CNN原理的链接:CNN原理介…

【Ai工具合集,一定有你需要的!】

花费了一天的时间测试了市面上各大Ai工具&#xff0c;然后帮大家整理总结出来了这些工具&#xff0c;一定记得点赞收藏保存&#xff0c;后面肯定会用到&#xff01; 使用说明 1.部分Ai工具需要魔法上网&#xff0c;请自行解决&#xff1b;部分工具需要收费&#xff0c;可以尝…

图神经网络:(处理点云)PointNet++的实现

文章说明&#xff1a; 1)参考资料&#xff1a;PYG官方文档。超链。 2)博主水平不高&#xff0c;如有错误还望批评指正。 3)我在百度网盘上传了这篇文章的jupyter notebook和有关文献。超链。提取码8848。 文章目录 简单前置工作学习文献阅读PointNet的实现模型问题 简单前置工作…

convLSTM2D 层使用方法解析(Keras库)

最近在研究时序图像分类问题&#xff0c;需要用到convLSTM层提取特征&#xff0c;所以在此仔细分析一下keras.layers.ConvLSTM2D层的使用方法。深度学习框架是tensorflow 官方文档&#xff1a;recurrent/#convlstm2d - Keras 中文文档 下面这部分内容摘自官方文档 ConvLSTM2D…

Axure 轮播图如何制作

近来在学习axure&#xff0c;用的版本为Axure 9&#xff0c;给大家讲一下怎么使用轮播图&#xff0c;老规矩保姆式教学法 一、作图 1.创建新的页面&#xff0c;方便我们做图 2.在元件库搜索“动态面板”字样&#xff0c;设置一个动态面板&#xff0c;为什么要设置呢&#xff…

IIC总线通讯协议学习

​ IIC(最简单的总线通讯,简单意味着通用和普适性) iic通讯一般采用一主多从的方式.同一时间要么在发送信息,要么在读取信息(半双工通讯) ​​​​​​​​​​​​​​ ​​​​ ​​​ 标准的写数据帧&#xff08;主机向从机写数据) 解释以上的写数据帧 S:起始信号(在SCL…

Linux学习---VMWare安装和CentOS7安装

1、 VMWare安装 1、VMware16安装包 链接&#xff1a;https://pan.baidu.com/s/1TKf5szN6k5Hk4HH4zqBgrg 提取码&#xff1a;zhm6 –来自百度网盘超级会员V1的分享 2、VMWare安装流程 &#xff08;1&#xff09;找到下载好的安装包&#xff0c;双击运行程序 &#xff08;2&…

云贝餐饮连锁V2-2.7.7 【新增】外卖新订单提醒

独立版&#xff1a;云贝餐饮连锁V2、版本更新至2.7.7&#xff0c;小程序、公众号版本&#xff0c;全插件&#xff0c;包含微信公众号小程序&#xff1b;包更新&#xff0c;独立版&#xff1b; 带商家端&#xff0c;修复收银台、排队点餐、堂食点餐&#xff1b;最新版更新了&…

【pytorch损失函数(3)】nn.L1Loss()和nn.SmoothL1Loss()

文章目录 【回归损失函数】L1&#xff08;MAE&#xff09;、L2&#xff08;MSE&#xff09;、Smooth L1 Loss详解1. L1 Loss&#xff08;Mean Absolute Error&#xff0c;MAE&#xff09;1.1 数学定义1.2 、使用场景与问题1.3 、如何使用 2. L2 Loss&#xff08;Mean Squared E…

最流行的开源 LLM (大语言模型)整理

本文对国内外公司、科研机构等组织开源的 LLM 进行了全面的整理。 Large Language Model (LLM) 即大规模语言模型&#xff0c;是一种基于深度学习的自然语言处理模型&#xff0c;它能够学习到自然语言的语法和语义&#xff0c;从而可以生成人类可读的文本。 所谓"语言模…