VS2015中Duilib界面使用OpenGL导入3DS模型(C++完整代码和源文件)

本文分为两部分:
(1)在Duilib窗口内创建win32子窗口
(2)在子窗口内使用OpenGL导入3DS模型

在MFC中使用OpenGL导入3DS模型的说明见另一篇文章:VS2015中MFC界面使用OpenGL导入3DS模型(C++完整代码和源文件)

0、实现思路

Created with Raphaël 2.2.0 开始(本文所建模型名称为DC10) 第1步:在SolidWorks中绘制三维模型,输出DC10.STL格式文件 第2步:将.STL文件导入3DSMax中确立纹理坐标,输出DC10.3DS格式文件 第3步:将DC10.3DS 文件再导入Deep Exploration中进行三维模型材质 、纹理的二次 处理,或直接输出DC10.cpp格式文件 第4步:新建win32控制台应用程序Win32Project1_DuilibTest,创建Duilib窗口以及子窗口 第5步:将DC10.cpp文件加入到Duilib项目中,使用OpenGL库函数在子窗口内进行渲染 结束

做了个简单的Duilib界面,并在子窗口内导入了DC10.3DS模型,控制模型自动缩放和旋转,效果如下所示,本篇文章将针对第4步和第5步进行详细记录,文章最后附有完整代码和源文件。
在这里插入图片描述

1、创建父窗口xml界面文件:Interface.xml

Interface.xml文件完整代码如下,只在界面中绘制了一个按钮,其中
button_off.pngbutton_on.png 是预设的按钮背景图片

<?xml version="1.0" encoding="utf-8" ?>
<Window size="800,480" caption="0,0,0,0">
	<Font name="微软雅黑" size="14" bold="false" italic="false" />
	<Default name="Button" value="height=&quot;60&quot; width=&quot;71&quot; normalimage=&quot;file=&apos;button_off.png&apos;&quot; pushedimage=&quot;file=&apos;button_on.png&apos;&quot; " />
	<VerticalLayout name="HJDemo" bkcolor="#FFE9EEF2">
		<Button name="Button_1" text="OpenGL" float="true" pos="600,100,0,0" font="0" pushedtextcolor="#FFFFFFFF" />
	</VerticalLayout>
</Window>

2、创建子窗口xml界面文件:SubInterface.xml

SubInterface.xml文件完整代码如下,空的界面

<?xml version="1.0" encoding="utf-8" ?>
<Window size="460,460" caption="0,0,0,0">
	<Font name="微软雅黑" size="14" bold="false" italic="false" />
	<VerticalLayout name="HJDemo_sub" bkcolor="#FF008080">
		
	</VerticalLayout>
</Window>

3、新建【win32控制台应用程序】

新建时选择win32-》控制台应用程序,项目名称为 Win32Project1_DuilibTest ,其余默认,新建完成,如下图所示,编译运行一下,以便生成Debug文件夹。
在这里插入图片描述

4、在项目根目录下的Debug文件夹内新建skin文件夹

xmlpng文件放进Debug-》skin文件夹内,如下图所示
在这里插入图片描述

6、添加Duilib窗口类

在【源文件】右键,使用【类向导】【添加类】,类命名为【CInterfaceWnd】,基类为【WindowImplBase】,如下图所示,完成添加。
在这里插入图片描述
此时提示WindowImplBase不是类名或结构名,是因为还没有配置Duilib环境,下面开始配置。

6、配置Duilib环境

(1)将Duilib库文件放在项目根目录下【lib】文件夹中,如下图所示
在这里插入图片描述
(2)在项目右键【属性】-》【配置属性】-》【VC++目录】-》编辑【库目录】-》添加新航【$(solutiondir)lib】-》【确定】-》【确定】,完成库目录的添加,如下图所示
在这里插入图片描述
(3)在项目右键【属性】-》【连接器】-》【输入】-》【附加依赖项】-》添加【$(SolutionDir)\lib\DuiLib_ud.lib】-》【确定】-》【确定】,如下图所示
在这里插入图片描述
(4)将Duilib文件夹放在项目根目录下,在stdafx.h头文件中加入Duilib头文件

//Duilib
#include <ObjBase.h>
#include "../Duilib/DuiLib/UIlib.h"
#include "../Duilib/DuiLib/Core/UIControl.h"
#include "..\Duilib\DuiLib\Utils\WinImplBase.h"
using namespace DuiLib;
#ifdef _DEBUG
#pragma comment (lib, "duilib_ud.lib")
#else
#pragma comment (lib, "duilib_u.lib")
#endif

//CString头文件
#include <atlstr.h>

(5)在【InterfaceWnd.h】文件中引入【#include “stdafx.h”】头文件(可删除自动添加的WinImplBase.h头文件引用,因为已经在stdafx.h中引用了),【InterfaceWnd.h】代码此时如下。

#pragma once
#include "stdafx.h"

class CInterfaceWnd :
	public WindowImplBase
{
public:
	CInterfaceWnd();
	~CInterfaceWnd();
};

(6)在项目属性\CC++\预处理器\预处理器定义\里添加 _WINDOWS
(7)在项目属性\链接\系统 里选择 窗口 (/SUBSYSTEM:WINDOWS)
编译运行通过,至此完成Duilib环境配置。

7、创建Duilib窗口

(1)Win32Project1_DuilibTest.cpp源文件

#include "stdafx.h"
#include "InterfaceWnd.h"

int APIENTRY _tWinMain(HINSTANCE hInstance,
	HINSTANCE hPrevInstance,
	LPTSTR    lpCmdLine,
	int       nCmdShow)
{
	CPaintManagerUI::SetInstance(hInstance);// 加载XML的时候,需要使用该句柄去定位EXE的路径,才能加载XML的路径

	CInterfaceWnd* wnd = new CInterfaceWnd(); // 生成对象
	wnd->Create(NULL, NULL, UI_WNDSTYLE_DIALOG, 0); // 创建DLG窗口
	wnd->CenterWindow(); // 窗口居中
	wnd->ShowModal();
	CPaintManagerUI::MessageLoop(); // 消息循环

	delete wnd; // 删除对象
	return 0;
}

(2)InterfaceWnd.h源文件

#pragma once
#include "stdafx.h"

class CInterfaceWnd :
	public WindowImplBase
{
public:
	CInterfaceWnd();
	~CInterfaceWnd();

	DUI_DECLARE_MESSAGE_MAP()

	virtual CDuiString GetSkinFolder() { return _T("skin"); };
	virtual CDuiString GetSkinFile() { return _T("Interface.xml"); };
	virtual LPCTSTR GetWindowClassName(void) const { return _T("InterfaceWnd"); };

	//Duilib通用窗口类封装
	virtual void InitWindow();
	virtual void OnClick(TNotifyUI& msg);
	HWND hWnd;

public:
	CPaintManagerUI* GetPaintManagerUI() { return &m_PaintManager; }

private:
	CPaintManagerUI* m_pParent;
	bool m_bZoomed;
	CPaintManagerUI* m_pPaintManager;
};

(3)InterfaceWnd.cpp源文件

#include "stdafx.h"
#include "InterfaceWnd.h"

DUI_BEGIN_MESSAGE_MAP(CInterfaceWnd, WindowImplBase)    //将不同的消息映射到对应的响应函数里面
DUI_ON_MSGTYPE(DUI_MSGTYPE_CLICK, OnClick)
DUI_END_MESSAGE_MAP()

CInterfaceWnd::CInterfaceWnd()
{
}

CInterfaceWnd::~CInterfaceWnd()
{
}

void CInterfaceWnd::InitWindow()//初始化窗口
{
	hWnd = m_PaintManager.GetPaintWindow();
}

void CInterfaceWnd::OnClick(TNotifyUI &msg)
{
}

编译运行成功,弹出如下界面
在这里插入图片描述

8、创建Duilib子窗口

(1)同样方法添加新类【COpenGLWnd】,基类同样为【WindowImplBase】
在这里插入图片描述
(2)OpenGLWnd.h源文件

#pragma once
#include "stdafx.h"

class COpenGLWnd :
	public WindowImplBase
{
public:
	COpenGLWnd();
	~COpenGLWnd();
	void Init(HWND hWndParent);
	void SetPos(HWND hWndParent, int X, int Y, int cx, int cy);
	virtual CDuiString GetSkinFolder() { return _T("skin"); };
	virtual CDuiString GetSkinFile() { return _T("SubInterface.xml"); };
	virtual LPCTSTR GetWindowClassName(void) const { return _T("OpenGLWnd"); };

	DUI_DECLARE_MESSAGE_MAP()
};

(3)OpenGLWnd.cpp源文件

#include "stdafx.h"
#include "OpenGLWnd.h"

DUI_BEGIN_MESSAGE_MAP(COpenGLWnd, WindowImplBase)    //将不同的消息映射到对应的响应函数里面
DUI_END_MESSAGE_MAP()

COpenGLWnd::COpenGLWnd()
{
}


COpenGLWnd::~COpenGLWnd()
{
}

void COpenGLWnd::Init(HWND hWndParent) //void Init(HWND hWndParent,POINT ptPos)
{
	Create(hWndParent, _T("CWin32UI"), UI_WNDSTYLE_DIALOG, 0);
}

void COpenGLWnd::SetPos(HWND hWndParent, int X, int Y, int cx, int cy)
{
	::SetWindowPos(*this, NULL, X, Y, cx, cy, SWP_SHOWWINDOW);
}

(4)InterfaceWnd.cpp更新为

#include "stdafx.h"
#include "InterfaceWnd.h"

DUI_BEGIN_MESSAGE_MAP(CInterfaceWnd, WindowImplBase)    //将不同的消息映射到对应的响应函数里面
DUI_ON_MSGTYPE(DUI_MSGTYPE_CLICK, OnClick)
DUI_END_MESSAGE_MAP()

CInterfaceWnd::CInterfaceWnd()
{
	// 构造一个新的COpenGL对象
	m_pOpenGLWnd = new COpenGLWnd();
}

CInterfaceWnd::~CInterfaceWnd()
{
	delete m_pOpenGLWnd;
	m_pOpenGLWnd = NULL;
}

void CInterfaceWnd::InitWindow()//初始化窗口
{
	hWnd = m_PaintManager.GetPaintWindow();
}

void CInterfaceWnd::OnClick(TNotifyUI &msg)
{
	if (msg.pSender->GetName() == _T("Button_1")) // 绘制按钮
	{
		if (m_pOpenGLWnd != NULL)
		{
			m_pOpenGLWnd->Init(*this);
			m_pOpenGLWnd->SetPos(hWnd, 380, 180, 460, 460); //300*300是子窗口的大小,但是opengl的绘图区域大小需要在xml里的windows属性size="300,300"设置
		}
	}
}

编译运行通过,弹出Duilib窗口界面,点击OpenGL按钮,弹出子窗口如下(深蓝色区域),至此子窗口创建完成
在这里插入图片描述

9、配置OpenGL文件

(1)将opengl所需要的文件复制到项目文件夹下,共三个文件夹:bin(存放.dll文件)、include(存放.h文件)、lib(存放.lib文件)

  • 【bin】文件夹放入:【glut.dll】和【glut32.dll】
  • 【include】文件夹内新建【GL】文件夹,【GL】文件夹内包含:【GLAUX.H】和【glut.h】
  • 【lib】文件夹放入:【GLAUX.LIB】、【glut.lib】和【glut32.lib】

(注:GLU.h和GL.h文件在系统内,不需要额外添加处理,如系统找不到,那么GL的lib、dll、h文件也同glut相关文件一样处理)
以下配置图片直接使用的MFC下配置OpenGL的截图,不更新了
在这里插入图片描述
(2)配置环境。在项目右击-》【属性】-》【配置属性】-》【VC++目录】-》编辑【包含目录】-》添加【$(solutiondir)include】-》确定-》编辑【库目录】-》添加【$(solutiondir)lib】-》确定-》【确定】
(注:确保所配置环境的属性与当前运行环境一致,如下图所示)
在这里插入图片描述
(3) 在【stdafx.h】中加入OpenGL头文件

//OpenGL
#include <GL/glut.h>
#include <GL/GLAUX.H>

配置完成,编译运行成功

10、将模型.cpp文件导入Duilib项目

(1)在【源文件】右键,使用【类向导】添加新类C3DSModel,如下图所示,并且在C3DSModel.h和C3DSModel.cpp中添加【#include “stdafx.h”】头文件**
在这里插入图片描述
(2)打开DC10.cpp文件,将除函数外的结构体、数组等复制到C3DSModel.h头文件中,并为函数添加声明,如下图所示
在这里插入图片描述
(3)将其余函数复制到C3DSModel.cpp文件中,并在函数名前加入【C3DSModel::】,如下图所示
在这里插入图片描述
编译通过,运行成功,但此时对话窗口并没有开始绘制3DS模型(文章后面贴出完整代码)

11、添加Duilib子窗口类COpenGLWnd

采用上述同样的方法添加新类COpenGLWnd
(1)OpenGLWnd.h源文件

#pragma once
#include "stdafx.h"
#include "C3DSModel.h"

class COpenGLWnd :
	public WindowImplBase
{
public:
	COpenGLWnd();
	~COpenGLWnd();
	void SetPos(HWND hWndParent, int X, int Y, int cx, int cy);
	virtual CDuiString GetSkinFolder() { return _T("skin"); };
	virtual CDuiString GetSkinFile() { return _T("SubInterface.xml"); };
	virtual LPCTSTR GetWindowClassName(void) const { return _T("OpenGLWnd"); };

	DUI_DECLARE_MESSAGE_MAP()

		
public:
	//添加的成员函数与成员变量
	int MySetPixelFormat(HDC hdc);
	LRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL & bHandled);
	void OnPaint();
	HDC hdc;
	HGLRC hglrc;
	GLfloat step, s;
	

	C3DSModel* m_p3DSModel;
	GLuint lid = 0;
};

(2)OpenGLWnd.cpp源文件

#include "stdafx.h"
#include "OpenGLWnd.h"

DUI_BEGIN_MESSAGE_MAP(COpenGLWnd, WindowImplBase)    //将不同的消息映射到对应的响应函数里面
DUI_END_MESSAGE_MAP()

COpenGLWnd::COpenGLWnd()
{
	m_p3DSModel = new C3DSModel();
	//给成员变量赋初值
	step = 0.0;
	s = 0.1;
}


COpenGLWnd::~COpenGLWnd()
{
	delete m_p3DSModel;
	m_p3DSModel = NULL;
}

void COpenGLWnd::SetPos(HWND hWndParent, int X, int Y, int cx, int cy)
{
	//子窗口相对于屏幕的位置
	::SetWindowPos(*this, NULL, X, Y, cx, cy, SWP_SHOWWINDOW);
}


// 设置像素格式函数
int COpenGLWnd::MySetPixelFormat(HDC hdc)
{
	PIXELFORMATDESCRIPTOR pfd = {
		sizeof(PIXELFORMATDESCRIPTOR),    // pfd结构的大小 
		1,                                // 版本号 
		PFD_DRAW_TO_WINDOW |              // 支持在窗口中绘图 
		PFD_SUPPORT_OPENGL |              // 支持 OpenGL 
		PFD_DOUBLEBUFFER,                 // 双缓存模式 
		PFD_TYPE_RGBA,                    // RGBA 颜色模式 
		24,                               // 24 位颜色深度 
		0, 0, 0, 0, 0, 0,                 // 忽略颜色位 
		0,                                // 没有非透明度缓存 
		0,                                // 忽略移位位 
		0,                                // 无累加缓存 
		0, 0, 0, 0,                       // 忽略累加位 
		32,                               // 32 位深度缓存     
		0,                                // 无模板缓存 
		0,                                // 无辅助缓存 
		PFD_MAIN_PLANE,                   // 主层 
		0,                                // 保留 
		0, 0, 0                           // 忽略层,可见性和损毁掩模 
	};

	int  iPixelFormat;

	// 为设备描述表得到最匹配的像素格式 
	if ((iPixelFormat = ChoosePixelFormat(hdc, &pfd)) == 0)
	{
		//MessageBox(_T("ChoosePixelFormat Failed"), NULL, MB_OK);
		return 0;
	}

	// 设置最匹配的像素格式为当前的像素格式 
	if (SetPixelFormat(hdc, iPixelFormat, &pfd) == FALSE)
	{
		//MessageBox(_T("SetPixelFormat Failed"), NULL, MB_OK);
		return 0;
	}

	return 1;
}

LRESULT COpenGLWnd::OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
	if (WindowImplBase::OnCreate(uMsg, wParam, lParam, bHandled) == -1)
		return -1;

	// TODO:  在此添加您专用的创建代码

	// 设置当前的绘图像素格式
	MySetPixelFormat(::GetDC(m_hWnd));
	// 创建绘图描述表
	hdc = ::GetDC(m_hWnd);
	// 创建渲染描述表
	hglrc = wglCreateContext(hdc);
	// 使绘图描述表为当前调用现程的当前绘图描述表 
	wglMakeCurrent(hdc, hglrc);

	return 0;
}

void COpenGLWnd::OnPaint()
{
	//CPaintDC dc(this); // device context for painting
	// TODO: 在此处添加消息处理程序代码

	//调用OpenGL绘图函数进行图形绘制
	glEnable(GL_TEXTURE_2D); // 启用纹理映射
	glShadeModel(GL_SMOOTH); // 启用阴影平滑
	glClearColor(0.0f, 0.0f, 0.0f, 0.5f); // 黑色背景
	glClearDepth(1.0f); // 设置深度缓存
	glEnable(GL_DEPTH_TEST); // 启用深度测试
	glDepthFunc(GL_LEQUAL); // 所作深度测试的类型
	glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // 真正精细的透视修正
													   //光源
	GLfloat LightAmbient[] = { 0.5f, 0.5f, 0.5f, 1.0f }; // 环境光参数
	GLfloat LightDiffuse[] = { 1.0f, 1.0f, 1.0f, 1.0f }; // 漫射光参数
	GLfloat LightPosition[] = { 12.0f, 10.0f, -10.0f, 1.0f }; // 光源位置
	glLightfv(GL_LIGHT1, GL_AMBIENT, LightAmbient); // 设置环境光
	glLightfv(GL_LIGHT1, GL_DIFFUSE, LightDiffuse); // 设置漫射光
	glLightfv(GL_LIGHT1, GL_POSITION, LightPosition); // 设置光源位置
	glEnable(GL_LIGHT1); // 启用一号光源
	glEnable(GL_LIGHTING);

	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);	//清除颜色缓存和深度缓存

	s += 0.0004;
	if (s>1.5)
		s = 0.1;
	step = step + 0.05;
	if (step > 360.0)
		step = step - 360.0;
	glPushMatrix();
	glScalef(s, s, s);//void glScalef(GLfloatx, GLfloaty, GLfloatz);x,y,z分别为模型在x,y,z轴方向的缩放比。
	glRotatef(step, 1.0, 0.0, 0.0);
	glRotatef(step, 0.0, 1.0, 0.0);
	glRotatef(step, 0.0, 0.0, 1.0);
	//DrawColorBox();
	if (lid == 0)
	{
		lid = m_p3DSModel->Gen3DObjectList();
	}
	glCallList(lid);

	glPopMatrix();
	glFlush();

	SwapBuffers(hdc);

	// Do not call CWnd::OnPaint() for painting messages
}

(3)OpenGLWnd.cpp源文件更新如下

#include "stdafx.h"
#include "InterfaceWnd.h"

DUI_BEGIN_MESSAGE_MAP(CInterfaceWnd, WindowImplBase)    //将不同的消息映射到对应的响应函数里面
DUI_ON_MSGTYPE(DUI_MSGTYPE_CLICK, OnClick)
DUI_END_MESSAGE_MAP()

CInterfaceWnd::CInterfaceWnd()
{
	// 构造一个新的COpenGL对象
	m_pOpenGLWnd = new COpenGLWnd();
}

CInterfaceWnd::~CInterfaceWnd()
{
	delete m_pOpenGLWnd;
	m_pOpenGLWnd = NULL;
}

void CInterfaceWnd::InitWindow()//初始化窗口
{
	hWnd = m_PaintManager.GetPaintWindow();
}

void CInterfaceWnd::OnClick(TNotifyUI &msg)
{
	if (msg.pSender->GetName() == _T("Button_1")) // 绘制按钮
	{
		if (m_pOpenGLWnd != NULL)
		{
			m_pOpenGLWnd->Create(hWnd, _T("CWin32UI"), UI_WNDSTYLE_DIALOG, 0);
			m_pOpenGLWnd->SetPos(hWnd, 380, 180, 460, 460); //300*300是子窗口的大小,但是opengl的绘图区域大小需要在xml里的windows属性size="300,300"设置
			while (1)
			{
				m_pOpenGLWnd->OnPaint();
			}
		}
	}
}

编译运行通过,至此实现在Duilib子窗口内导入3DS模型,并旋转和缩放,点击OpenGL按钮开始绘制

12、存在问题

虽然导入了3DS模型,但是还存在以下几点问题未进行编写:

  1. 子窗口内绘制模型时,父窗口消息将无法再响应,需采用并发线程,建立两条消息队列
  2. 在父窗口Interface.xml文件中将windows的属性caption="0,0,0,0"改为caption=“0,0,0,60”,即可实现窗口拖动(在界面最上方按住鼠标左键拖动),但此时子窗口并不会随之移动,因为子窗口在创建时setPos是相对屏幕位置设置的,偶两种解决思路:
    (1)创建Duilib自定义控件,效果类似Button、Option这种控件,封装进Duilib库,以后可以直接调用
    (2)子窗口位置由【相对屏幕】更改为【相对程序】位置,父窗口位置一旦发生改变,子窗口位置随之改变

以上问题,将后续发文详细说明。
本文完整程序代码下载地址:https://download.csdn.net/download/u012293114/12104631

您可以使用duilib库来在C++的DLL程序使用XML设计的UI界面duilib是一个开源的UI库,提供了丰富的控件和工具,支持使用XML来设计UI界面。您可以使用duilib的页面设计器工具来设计您的UI界面,并将其保存为XML格式,然后在您的DLL程序使用duilib的UI模块来加载和显示这个XML文件。在使用duilib的UI模块时,您需要连接到duilib的核心库和UI库,以便在您的程序使用duilib的UI组件。 以下是使用duilib的基本步骤: 1. 下载duilib库,并解压到您的项目目录。 2. 在您的C++项目添加duilib的头文件和库文件。 3. 在您的代码调用duilib的初始化函数和反初始化函数。 4. 使用duilib的页面设计器工具来设计您的UI界面,并将其保存为XML格式。 5. 在您的代码使用duilib的UI模块来加载和显示这个XML文件。 下面是一个简单的示例代码,展示了如何使用duilib来加载和显示XML界面: ```c++ #include <Windows.h> #include "Duilib/UIlib.h" using namespace DuiLib; int APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) { switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: // 初始化duilib ::CoInitialize(NULL); CPaintManagerUI::SetInstance(hModule); break; case DLL_PROCESS_DETACH: // 反初始化duilib CPaintManagerUI::Term(); ::CoUninitialize(); break; } return TRUE; } // 显示XML界面 void ShowXmlUI(HWND hWndParent) { // 创建duilib窗口,并加载XML文件 CPaintManagerUI paint_manager; CDialogBuilder builder; CControlUI* pRoot = builder.Create(_T("myui.xml"), NULL, NULL, &paint_manager); if (pRoot == NULL) return; // 设置duilib窗口的父窗口为hWndParent,并显示窗口 HWND hWnd = paint_manager.Create(hWndParent, _T("duilib window")); paint_manager.AttachDialog(pRoot); paint_manager.ShowWindow(true); } ``` 在上面的示例代码,`DllMain`函数用于初始化和反初始化duilib,`ShowXmlUI`函数用于创建duilib窗口,并加载并显示XML界面。您可以将上面的代码集成到您的DLL程序,以便在需要时显示XML界面
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

汪蛋

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值