D3DX Utility library概述

D3DX 是一个静态库,容易使用在发布的产品上。D3DX 也提供3D 图形应用程序公共的操作。D3DX包含下面几个方面:抽象数据类型,helper对象,triangle meshes,resource function和一些其他函数。

具体类提供了颜色,材质,向量,矩阵,面和quaternion。他们实现为C++类,并且也提供了一些操作在这些类上全局函数。helper对象实现了矩阵堆栈,text rendering,spirites和multi-pass 渲染效果,render target assistance。这些对象是以COM对象实现的。

D3DX的大多数high level的操作都是基于triangle meshes。Meshes包含很多不同的种类,都是用COM来实现的。

Headers and libraries

D3DX 是通过一堆头文件和一个静态库提供的。这个库有debug和release两个版本。对于调试库,它也提供一个dll版本,但是这个版本不能用在发布产品。

如果你的应用程序要使用D3DX,你应该包含<d3dx9.h>头文件。这个头文件包含所有的D3DX头文件:<d3dx9core.h>,<d3dxeffect.h>,<d3dx9math.h>,<d3dx9mesh.h>,<d3dx9shape.h>,<d3dx9tex.h>。

d3dx9.lib用在realse的build里面,d3dx9dt.lib包含一些附加的调试信息,用在debug版里面。d3dx9d.lib用在debugging build里面。

数据类型

D3DX 提供了一些concrete datatypes和一些管理他们的函数。一个concrete dataypes能够让程序员了看到所有的成员和实现,而对于抽象的类型,程序员只能看到接口。D3DX 把colors, vectors,planes, quaternions和matrices实现为concrete datatypes。他们的类分别是D3DXCOLOR, D3DXVECTOR2,D3DXVECTOR3,D3DXVECTOR4, D3DXPLANE, D3DXQUATERNION和D3DXMATRIX(4*4同次转换矩阵)。

Helper Objects

与C++实现的concrete datatypes相比,D3DX也提供了实现为COM对象的抽象datatypes。ID3DXMatrixStack 提供了scene graph中使用的转换矩阵的堆栈。ID3DXFont提供了GDI实现的字体渲染. ID3DXSprite提供了简单的基于2D的Sprites。 ID3DXRenderToSurface提供了渲染到target surface的简化接口。类似,ID3DXRenderToEnvMap提供了渲染到环境map纹理的简化接口。

Meshes

D3DX 提供了几个mesh对象封装被索引的三角形列表。Mesh simplification 和 progressive 都将会支持。ID3DXMesh把一个形状封装成一个三角形mesh。ID3DXPMesh接口封装progressive mesh refinement。ID3DXBashMesh是ID3DXMesh和ID3DXPMesh的基接口。ID3DXSPMesh封装了任意的mesh simplication。ID3DXSkinInfo封装了skinned mesh。 D3DX 也提供了从.x文件读写mesh对象的操作。

资源

图片和纹理都是几乎每个Direct3D应用程序都要使用的资源。D3DX提供了大量的创建,初始化surfaces 以及从文件,win32 资源,内存block里面读取纹理的操作。D3DX 也能读取.bmp,.dds,.dib,.jpg,.png,.ppm和.tga文件格式。 D3DX能够将资源数据写入到 DirectDraw surface(.dds)文件和windows bitmap format(.bmp)文件。

Disc上的文件数据可以通过他们的文件名引用。内存里面的文件通过一个指令内存块的指针引用。win32资源文件可以通过包含资源和资源名称的模块句柄所引用。win32资源对.bmp数据可以是RT_BITMAP类型,对其他的文件格式是RT_RCDATA。注意一定不要把win32 resource和存储在可执行文件上的数据混淆了。

Resource Image Information

D3DX支持的最简单的操作是读取一个图片文件的维度和格式信息。 D3DXGetImageInfoFromFile,D3DXGetImageInfoFromFileMemory和 D3DXGetImageInfoFromResource分别从硬盘文件,内存文件和win32资源形式的文件里面获取图片的信息。

typedef struct _D3DXIMAGE_INFO

{

UINT Width;

UINT Height;

UINT Depth;

UINT MipLevels;

D3DFORMAT Format;

D3DRESOURCETYPE ResourceType;

D3DXIMAGE_FILEFORMAT ImageFileFormat;

} D3DXIMAGE_INFO;

对于图片,Depth是1。大部分图片的MipLevels为1,但是.dds文件能存储整个mipmap chains;ResourceType只是一个文件是否包含纹理,volume纹理或者立方体纹理;Format 成员给出了与文联里面的数据格式最匹配的像素格式;ImageFileFormat指示了资源数据的文件格式,它的值包含在 D3DXIMAGEF_FILEFORMAT里面。

typedef enum _D3DXIMAGE_FILEFORMAT

{

D3DXIFF_BMP = 0,

D3DXIFF_DDS = 4,

D3DXIFF_DJB = 6,

D3DXIFF_JPG = 1,

D3DXIFF_PNG = 3,

D3DXIFF_PPM= 5,

D3DXIFF_TGA = 2  

} D3DXIMAGE_FILEFORMAT;

Resource Requirements

装载资源的公共任务是将文件的像素维度与设备requirements的匹配。D3DX 提供函数D3DXCheckTextureRequirements,D3DXCheckCubeTextureRequirements和 D3DXCheckVolumeTextureRequirements来调整资源的维度,mipmap levels的数目和像素格式来适应设备的requirements。

Format Conversion

D3DX 提供了将像素数据从一种格式转换到另一种格式的方法。它包含color-space的转换,channel 缩放,压缩和解压缩以及过滤。D3DXLoadSurfaceFromSurface执行了surface的格式转换。 D3DXLoadVolumeFromVolume执行基于volume的转换。为了执行纹理之间的转换,GetSurfaceLevel和 GetVolumeLevel方法获取纹理里面包含的surface或者volume的接口指针。

HRESULT ::D3DXLoadSurfaceFromSurface(IDirect3DSurface9 * destination,

cost PALETTEENTRY * dest_palette,

const RECT * dest_rect,

IDirect3DSurface9 * source,

const PALETTEENTRY * source_palette,

const RECT * source_rect,

DWORD filter,

D3DCOLOR color_key );

HRESULT ::D3DXLoadVolumeFromVolume(IDirect3DVolume9 *destination,

const PALETTEENTRY * dest_palette,

const D3DBOX* dest_box,

IDirect3DVolume9 * source,

const PALETTEENTRY * source_palette,

const D3DBOX * source_box,

DWORD filter,

D3DCOLOR color_key);

dest_palette和source_palette参数指向包含256个PALETTEENTRY结构体的内存,源和目的格式都是 D3DFMT_P8。当源和目的都不是被索引的格式,这些参数将可能是空。dest_rect和source_rect参数在源和目的面上的某个子矩形运行转换操作。dest_box和source_box参数的操作方式类似于volumes。当这些参数指向源和目的地不同大小的区域时,D3DX在源区域执行filtering来匹配目的区域。过滤kernel通过filter参数指定,它的值可能是D3DX_DEFAULT,或者下面的值:

D3DX_FILTER---------textbf

#define D3DX_FILTER_NONE (1<<0)

#define D3DX_FILTER_POINT (2<<0)

#define D3DX_FILTER_LINEAR (3<<0)

#define D3DX_FILTER_TRIANGLE (4<<0)

#define D3DX_FILTER_MIRROR_U (1<<16)

#define D3DX_FILTER_MIRROR_V (2<< 16)

#define D3DX_FILTER_MIRROR_W (4<< 16)

#define D3DX_FILTER_MIRROR (7<<16)

#define D3DX_FILTER_DITHER (8<<16)

D3DX_FILTER_NONE指定超出源区域范围的目的区域的颜色将是全透明黑,它将不再会有缩放和filtering发生。D3D_DEFAULT 等同于D3DX_FILTER_TRIANGLE和D3DX_FILTER_DITHER的结合体。 D3DX_FILTER_POINT,D3DX_FILTER_LINEAR,D3DX_FILTER_TRIANGLE,D3DX_FILTER_BOX 指定filter kernel将应用到源区域。Point filtering是最快的缩放方法,但是它产生的锯齿最多。Linear filtering对于surface使用2*2 像素临近区域,或者对于volume使用2*2*2像素临近区域,它在源像素的临近区域线性插值来计算目的像素值。线性过滤的开销要大于点过滤,但是它能产生更高质量的图片。三角形过滤器使用的临近区域将会与源区域和目的区域的大小成正比,它的开销最大。box 过滤器将使用2*2的surface临近区域,或者2*2*2的volume区域,临近区域像素的平均值将作为目的像素值。Box filter主要是用于计算mipmap levels,但是仍然引起很多锯齿。

Mirror标志控制了源图片x,y,z轴的repetition。D3DX_FILTER_MIRROR标志mirror了源图片所有的轴。 D3DX_FILTER_DITHER enalbe 了源像素到目的像素的4*4有序dither。 Dithering 在减少源像素的颜色深度的时候最有用,它能阻止产生banding artifacts。

最后,color_key参数允许应用程序在源区域指定一个像素值,它将在处理过程中被全透明黑取代。

Creating Texture Resources

D3DX提供了两种形式的函数从磁盘文件,内存文件以及win32 资源文件创建纹理资源。第一种使用资源checking和filtering 函数来构造一个资源,可能会resize这个资源以及进行格式转换。 第二种形式允许应用程序控制资源创建的过程。

  • Creating Uninitialized Textures

D3DXCreateTexture, D3DXCreateCubeTexture, D3DXCreateVolumeTexture 创建一个内容为未初始化的纹理资源。你能够在应用程序里面初始化纹理资源的内容。

HRESULT ::D3DXCreateTexture(IDirect3DDevice9 * device,

&nbp; UINT width,

UINT height,

UINT mip_levels,

DWORD usage,

D3DFORMAT format,

D3DPOOL pool,

IDirect3DTexture9 ** result);

HRESULT ::D3DXCreateCubeTexture(IDirect3DDevice9 * device,

UINT Size,

UINT mip_levels,

DWORD usage,

D3DFORMAT format,

D3DPOOL pool,

IDirect3DCubeTexture9 ** result);

HRESULT ::D3DXCreateVolumeTexture(IDirect3DDevice9 * device,

UINT width,

UINT height,

UINT depth,

UINT mip_levels,

DWORD usage,

D3DFORMAT format,

D3DPOOL pool,

IDirect3DVolumeTexture9 ** result);

  • Creating Textures from Files

D3DXCreateCubeTextureFromFile, D3DXCreateTextureFromFile, D3DXCreateVolumeTextureFromFile 从磁盘文件创建纹理资源。这些函数都能从磁盘文件里面取到像素的维度和像素格式,并且调整维度和格式来满足设备对资源的需求。文件里面的像素数据读进内存,并且可能会转化成资源使用的像素格式。

HRESULT ::D3DXCreateTextureFromFile(IDirect3DDevice9 * device,

LPCTSTR filename,

&nsp; IDirect3DTexture9 ** result);

HRESULT ::D3DXCreateCubeTextureFromFIle(IDirect3DDevice9 * device,

LPCTSTR filename,

IDirect3DTexture9 **result);

HRESULT ::D3DXCreateVolumeTextureFromFile(IDirect3DDevice9 * device,

LPCTSTR filename,

IDirect3DTexture9 ** result);

纹理资源可以从任何支持的文件格式里面创建。cube 纹理只能从.dds文件里面创建。volume可以从包含整个volume的.dds文件里面创建,或者从图片文件里面创建一个volume,它只包含一个slice。

扩展的纹理创建函数允许应用程序控制所有的参数。

HRESULT ::D3DXCreateTextureFromFileEx(IDirect3DDevice9 * device,

LPCTSTR filename,

UINT width,

UINT height,

UINT mip_levels,

DWORD usage,

D3DFORMAT format,

D3DPOOL pool,

DWORD filter,

DWORD mip_filter,

D3DCOLOR color_key,

D3DXIMAGE_INFO * info,

PALETTEENTRY * palette,

IDirect3DTexture9 ** result);

HRESULT ::D3DXCreateCubeTextureFromFileEx(IDirect3DDevice9 * device,

LPCTSTR filename,

UINT size,

UINT mip_levels,

DWORD usage,

D3DFORMAT format,

D3DPOOL pool,

DWORD filter,

DWORD mip_filter,

D3DCOLOR color_key,

D3DXIMAGE_INFO * info,

PALETTEENTRY * palette,

IDirect3DCubeTexture9 ** result);

HRESULT ::D3DXCreateVolumeTextureFromFileEx(IDirect3DDevice9 * device,

LPCTSTR filename,

UINT width,

UINT height,

UINT mip_levels,

DWORD usage,

D3DFORMAT format,

D3DPOOL pool,

DWORD filter,

&nbp; DWORD mip_filter,

D3DCOLOR color_key,

D3DXIMAGE_INFO * info,

PALETTEENTRY * palette,

IDirect3DVolumeTexture9 ** result);

filter 参数控制了图片转换成纹理资源most detailed level的filtering方式,mip_filter参数控制了mipmap levels的创建。当filter为D3DX_DEFAULT时,它将使用dithering和三角形过滤的混合方式。当mip_filter为空 D3DX_DEFAULT时,一个box filter将用于产生mipmap levels。info参数将返回构造纹理的图片文件的信息。palette参数返回资源装载的palette。

  • Creating Textures From Files In Memory

 D3DXCreateTextureFromFileInMemory, D3DXCreateCubeTextureFromFileInMemory, D3DXCreateVolumeTextureFromFileInMemory用来通过内存文件创建纹理。

Ex 形式的函数类似于先前讨论的纹理创建函数。

HRESULT ::D3DXCreateTextureFromFileInMemory(IDirect3DDevice9 * device,

const void * data,

UINT size,

IDirect3DTexture9 ** result);

HRESULT ::D3DXCreateCubeTextureFromFileInMemory(IDirect3DDevice9 * device,

const void * data,

UINT size,

IDirect3DCubeTexture9 ** result);

HRESULT ::D3DXCreateVolumeTextureFromFileInMemory(IDirect3DDevice9 * device,

const void * data,

UINT size,

IDirect3DCubeTexture9 ** result);

HRESULT ::D3DXCreateTextureFromFileInMemoryEx(IDirect3DDevice9 * device,

const void * data,

&nbp; UINT size,

UINT width,

UINT height,

UINT mip_levels,

DWORD usage,

D3DFORMAT format,

D3DPOOL pool,

DWORD filter,

DWORD mip_filter,

D3DCOLOR color_key,

D3DXIMAGE_INFO * info,

PALETTEENTRY * palette,

IDirect3DTexture9 ** result);

HRESULT ::D3DXCreateCubeTextureFromFileInMemoryEx(IDirect3DDevice9 * device,

const void * data,

UINT size,

UINT Size,

&nsp; UINT mip_levels,

DWORD usage,

D3DFORMAT format,

D3DPOOL pool,

DWORD filter,

DWORD mip_filter,

D3DCOLOR color_key,

D3DXIMAGE_INFO * info,

PALETTEENTRY * palette,

IDirect3DCubeTexture9 ** result);

HRESULT ::D3DXCreateVolumeTextureFromFileInMemoryEx(IDirect3DDevice9 * device,

const void * data,

UINT size,

UINT width,

UINT height,

UINT mip_levels,

DWORD usage,

D3DFORMAT format,

D3DPOOL pool,

DWORD filter,

DWORD mip_filter,

D3DCOLOR color_key,

D3DXIMAGE_INFO * info,

PALETTEENTRY * palette,

IDirect3DVolumeTexture9 ** result);

  • Creating Textures From Resource

HRESULT ::D3DXCreateTextureFromResource(IDirect3DDevice9 * device,

HMODULE module,

LPCTSTR resource ,

IDirect3DTexture9 ** result);

HRESULT ::D3DXCreateCubeTextureFromResource(IDirect3DDevice9 * device,

HMODULE module,

LPCTSTR resource ,

IDirect3DCubeTexture9 ** result);

HRESULT ::D3DXCreateVolumeTextureFromResource(IDirect3DDevice9 * device,

HMODULE module,

LPCTSTR resource ,

IDirect3DVolumeTexture9 ** result);

HRESULT ::D3DXCreateTextureFromResourceEx(IDirect3DDevice9 * device,

&nbs; HMODULE module,

LPCTSTR resource ,

UINT width,

UINT height,

UINT mip_levels,

DWORD usage,

D3DFORMAT format,

D3DPOOL pool,

DWORD filter,

DWORD mip_filter,

D3DCOLOR color_key,

D3DXIMAGE_INFO * info,

PALETTEENTRY* palette,

IDirect3DTexture9 ** result);

HRESULT ::D3DXCreateCubeTextureFromResourceEx(IDirect3DDevice9 * device,

HMODULE module,

LPCTSTR resource ,

UINT Size,

UINT mip_levels,

DWORD usage,

D3DFORMAT format,

D3DPOOL pool,

DWORD filter,

DWORD mip_filter,

D3DCOLOR color_key,

D3DXIMAGE_INFO * info,

PALETTEENTRY* palette,

IDirect3DCubeTexture9 ** result);

HRESULT ::D3DXCreateVolumeTextureFromResourceEx(IDirect3DDevice9 * device,

HMODULE module,

LPCTSTR resource ,

UINT width,

UINT height,

UINT mip_levels,

DWORD usage,

D3DFORMAT format,

D3DPOOL pool,

nbsp; DWORD filter,

DWORD mip_filter,

D3DCOLOR color_key,

D3DXIMAGE_INFO * info,

PALETTEENTRY* palette,

IDirect3DVolumeTexture9 ** result);

Loading Resource

如果你已经有了一个存在的surface或者纹理资源,并且想要把图片装载到资源里面,你能够使用D3DX把内容读入到surface。对于一个纹理或者 cube纹理资源,你能取到特定level的surface接口指针,然后把数据装载到surface。对于volume纹理,你能取得特定level的 volume接口指针,然后把数据装载到volume。surface数据将是一连窜的scanline,从最底部的scanline开始,相邻两个 scanline的offset是pitch个字节。 volume数据将是一连串的slices,slice_pitch和row_pitch分别是volume里相邻两个的slices的距离和slice 里面相邻两行的距离。

HRESULT ::D3DXLoadSurfaceFromMemory(IDirect3DSurface9 * destination,

const PALETTEENTRY * dest_palette,

const RECT * dest_rect,

const void * source,

D3DFORMAT format,

UINT pitch,

const PALETTEENTRY * source_palette,

const RECT * source_rect,

DWORD filter,

D3DCOLOR color_key);

HRESULT ::D3DXLoadSurfaceFromFile(IDirect3DSurface9 * destination,

const PALETTEENTRY * dest_palette,

cost RECT * dest_rect,

const void * data,

UINT size,

const RECT * source_rect,

DWORD filter,

D3DCOLOR color_key,

D3DXIMAGE_INFO * info);

HRESULT ::D3DXLoadSurfaceFromResource(IDirect3DVolume9 * destination,

const PALETTEENTRY * dest_palette,

const RECT * dest_rect,

HMODULE module,

LPCTSTR resource,

const RECT * source_rect,

DWORD filter,

D3DCOLOR color_key,

D3DXIMAGE_INFO * info);

HRESULT ::D3DXLoadVolumeFromMemory(IDirect3DVolume9 * destination,

const PALETTEENTRY * dest_palette,

const D3DBOX* dest_box,

const void * source,

D3DFORMAT format,

&nsp; UINT row_pitch,

UINT slice_pitch,

const PALETTEENTRY * source_palette,

const D3DBOX* source_box,

DWORD filter,

D3DCOLOR color_key);

HRESULT ::D3DXLoadVolumeFromFile(IDirect3DVolume9 * destination,

const PALETTEENTRY * dest_palette,

const D3DBOX* dest_box,

const void * data,

UINT size,

const D3DBOX* source_box,

DWORD filter,

D3DCOLOR color_key,

D3DXIMAGE_INFO * info);

HRESULT ::D3DXLoadVolumeFromResource(IDirect3DVolume9 * destination,

const PALETTEENTRY * dest_palette,

const D3DBOX* dest_box,

HMODULE module

LPCTSTR resource,

const D3DBOX* source_box,

&nsp; DWORD filter,

D3DCOLOR color_key,

D3DXIMAGE_INFO * info);

Saving Resources

D3DX能够将surface, texture和volume texture资源数据保存到.bmp和.dds文件格式。

HRESULT ::D3DXSaveSurfaceToFile(LPCTSTR filename

D3DXIMAGE_FILEFORMAT file_format,

IDirect3DSurface9 * source,

const PALETTEENTRY * palette,

const RECT * rect);

HRESULT ::D3DXSaveTextureToFile(LPCTSTR filename

D3DXIMAGE_FILEFORMAT file_format,

IDirect3DBaseTexture9 * source,

const PALETTEENTRY * palette );

HRESULT ::D3DXSaveVolumeToFile(LPCTSTR filename

D3DXIMAGE_FILEFORMAT file_format,

IDirect3DVolume9 * source,

const PALETTEENTRY * palette ,

const D3DBOX * box);

Filling Textures

除了将资源保存到文件外,D3DX提供一种方法来填充纹理资源。

HRESULT ::D3DXFillTexture(IDirect3DTexture9 * texture, LPD3DXFILL2D fill_proc, void * context);

HRESULT ::D3DXFillCubeTexture(IDirect3DCubeTexture9 * texture, LPD3DXFILL3D fill_proc, void * context);

HRESULT ::D3DXFillVolumeTexture(IDirect3DVolumeTexture9 * texture, LPD3DXFILL3D fill_proc, void * context);

typedef void (*LPD3DXFILL2D)(D3DXVECTOR4 * result, D3DXVECTOR2 * coord, D3DXVECTOR2 * size, void * context);

typedef void (*LPD3DXFILL3D)(D3DXVECTOR4 * result, D3DXVECTOR3 * coord, D3DXVECTOR3 * size, void * context);

Filtering Textures

当应用程序改变了一个mipmapped texture的most detailed level时,less detailed level需要重新生成。D3DX提供了单个函数以filtering方式创建mipmap levels。

HRESULT ::D3DXFilterTexture(IDirect3DBaseTexture9 * texture, const PALETTEENTRY * palette, UINT level, DWORD filter);

Creating Normal Maps

D3DX 从一个height field创建一个法线图。

HRESULT ::D3DXComputeNormalMap(IDirect3DTexture9 * destination,

IDirect3DTexture9 * source,

const PALETTEENTRY * palette,

DWORD flags,

DWORD channel,

float amplitude);

channel参数指定那个height field的那个通道用于elevation。

#define D3DX_CHANNEL_RED (1<<0)

#define D3DX_CHANNEL_BLUE (1<<1)

#define D3DX_CHANNEL_GREEN (1<<2)

#define D3DX_CHANNEL_ALPHA (1<<3)

#define D3DX_CHANNEL_LUMINANCE (1<<4)

flags参数提供了法线图计算的选项。mirror 标志控制x,y方向height field的repetition。Occlusion计算per-pixel的occlusion值,并且将它存放在法线图的alpha通道。

#define D3DX_NORMALMAP_MIRROR_U (1<<16)

#define D3DX_NORMALMAP_MIRROR_V (2<<16)

#define D3DX_NORMALMAP_MIRROR (3<<16)

#define D3DX_NORMALMAP_INVERTSIGN (8 << 16)

#define D3DX_NORMALMAP_COMPUTE_OCCLUSION (16 << 16)

Miscellaneous

  • Macros

const float D3DX_PI;

const float D3DX_1BYPI;

float D3DXToRadian(float degrees);

float D3DXToDegree(float radians);

  • Fresnel's Formulas

Error Handling

LPCTSTR ::DXGetErrorString9(HRESULT hr);

LPCTSTR ::DXGetErrorDescription9(HRESULT hr);

HRESULT ::D3DXGetErrorString(HRESULT hr, LPTSTR pBuffer, UINT BufferLen);

ID3DXBuffer

HRESULT ::D3DXCreateBuffer(DWORD size, ID3DXBuffer ** result);

Vertex Declarations

 UINT ::D3DXGetFVFVertexSize(DWORD fvf);

HRESULT ::D3DXDeclaratorFromFVF(DWORD fvf, DWORD result[MAX_FVF_DECL_SIZE]);

HRESULT ::D3DXFVFFromDeclarator(const DWORD * declaration, DWORD * size);

Intersection Testing

D3DX 提供函数计算射线与三角形相交。

BOOL ::D3DXIntersectTri(const D3DXVECTOR3 * p0,

const D3DXVECTOR3 * p1,

const D3DXVECTOR3 * p2,

const D3DXVECTOR3 * position,

const D3DXVECTOR3 * direction

float * u,

float * v,

float * distance);

D3DX 也提供了函数D3DXSphereBoundProbe和D3DXBoxBoundProbe来测试射线与bounding volume的相交。

Shader Assembly

D3DX 提供了函数将文本shader指令转化成shader token 数组。

D3DXAssembleShader,D3DAssembleShaderFromFile,D3DXAssembleShaderFromResource来实现这样的功能。

声明:

转载,from: http://blog.csdn.net/weili_2007

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值