




已阅读5页,还剩29页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
简介Simple DirectMedia Layer, 简称SDL,是一个自由的跨平台的多媒体开发包,主要通过OpenGL和2D视频帧缓冲(framebuffer)提供对音频、键盘、鼠标、游戏操纵杆 (joystick)和3D硬件的底层访问。它被广泛的应用于MPEG回放软件、模拟器和多个著名游戏中,如获得大奖的文明:权倾天下 (Civilization: Call To Power)的Linux移植版本。它的官方站点是:/ ,还有一个非常个性的LOGO(图1)。在Win32编程中,如果要操纵2D图像,可以选择使用GDI或者DirectDraw,前者速度较慢,而后者是特定针对Microsoft平台的,在非Win32平台上移植会带来很大的麻烦。这时,你可以选择使用SDL。SDL支持多种平台:Linux、 Windows, BeOS, MacOS Classic, MacOS X, FreeBSD, OpenBSD, BSD/OS, Solaris, IRIX和QNX,同时也部分支持部分其他平台:Windows CE, AmigaOS, Dreamcast, Atari, NetBSD, AIX, OSF/Tru64, RISC OS和SymbianOS。当然SDL本身是针对2D图像编程的,如果使用到3D编程,那么需要将SDL和OpenGL结合使用。SDL是用C编写的,但是也支持C+,同时其他多种语言,下面给出了其他语言的SDL的开发包的相关信息:AdaAdaSDL - /projects/adasdl/C#SDL.Net - /Eiffelewg - /ErlangESDL - /cslab/dgud/esdl/EuphoriaSDL_Wrap - /sdl_wrap.zipGuileguile-sdl - /projects/guile-sdl/Java JSDL - /sdljava - LispCL-SDL - /SDL for Corman Common Lisp - /lisp_sdl.php3LualuaSDL - /wiki/LuaModuleLuaSdlMLSDLML - http:/www.HardcoreP/Freeware/SDLML.htmlOCamlSDL - /Objective CSDLOBJC - /projects/sdlobjc/PascalSDL4Freepascal - /JEDI-SDL - /Jedi:TEAM_SDL_HOMEPerlSDLPerl - PHPPHP SDL module - PikeNatively supported (module SDL) - http:/pike.ida.liu.se/PliantPligame - /Python PyGame - /Ruby Ruby/SDL - http:/www.kmc.kyoto-u.ac.jp/ohai/index.en.htmlRUDL - 功能视频设置8bpp或更高的任意色彩深度的视频模式。如果某个模式硬件不支持,可以选择转化为另一模式。直接写入线性的图像帧缓冲(framebuffer)。用颜色键值(colorkey)或者alpha混合属性创建用于绘图的表面(surface)。Surface的blit能自动的转化为目标格式。blit是优化过的,并能使用硬件加速。x86平台上有针对MMX优化过的blit。硬件加速的blit和fill(填充)操作,如果硬件支持的话。事件提供以下事件:o 应用程序的visibility(可视性)发生改变o 键盘输入o 鼠标输入o 用户要求的退出每种事件都能通过SDL_EventState()关闭或者打开。事件经由用户指定的过滤函数再被加入到内部的事件队列。线程安全的事件队列。音频设置8位和16位的音频,单声道或者立体声,如果格式硬件不支持,可以选择转换。由独立的线程执行音频部分,并提供用户回调(callback)机制。设计上考虑到了客户定制的软混音器,但实际上在例程中就包含了一个完整的音频/音乐输出库。CD音频完整的CD音频控制API线程简单的线程创建API用于同步的简单的二进制信号量(semaphores)定时器读取已流逝的毫秒数。等待指定的毫秒数。设置一个10毫秒精度的周期性定时器。字节序无关侦测当前系统的字节序快速转换数据的函数读写指定字节序的数据下载SDL的官方下载地址为/download-1.2.php, 最新版本为1.2.8,分为运行库Runtime Library和开发库Development Library,使用SDL开发需要下载的是后者。由于SDL支持多平台和多个开发工具如VC6、Visual Studio.NET 2003、Dev-C+等等,所以可以根据需要选择合适自己的平台版本。由于笔者采用VC6给朋友们讲解SDL的使用,因此文章中只介绍了VC6下的安 装方式,并使用了一个小例子做说明。如果您使用其他的平台和工具,请在官方网站上查找相应的说明并按照要求去安装使用。VC6下SDL的安装和初步使用首先,我们为所有的工程创建一个文件夹tutorial,将下载的开发库SDL-devel-1.2.8-VC6.zip拷贝到tutorial下并解压,并保证如下的文件夹层次(图2)如下:图2下面我们打开Visual Studio6.0,开发一个非常简单的小例子。选择File-New,新建一个工程,选择Win32 Application,将工程gp保存为tutorial目录下,如图3所示。图3在图4中,保持默认设置,点击Finish。图4为了使用SDL,我们需要进行相关的设置,选择Project-Settings.,选择C/C+属性页,在Category中选择 Code Generation,在Use run-time library中选择Debug Multithreaded DLL,如图5所示。图5在Category中选择Preprocessor,在Additional include directories的文本框中填上.SDL-1.2.8include,如图6所示。 图6选择Link属性页,在Object/library modules文本框的首部增加SDLmain.lib和sdl.lib,如图7所示。 图7仍然是Link属性页,选择Category中的Input,在Additional library path文本框中填写.SDL-1.2.8lib,如图8所示。图8这样我们就完成了编程前的设置工作,不过这是针对Debug版本的,如果要设置Release版本,需要选择Build-Set Active Configuration,选择Release,然后再次如上配置一次。下面我们正式开始编程,将E:tutorialSDL-1.2.8libSDL.dll拷贝到gp文件夹下,然后给gp工程增加一个C+文件main.cpp。如图9所示。图9将以下代码拷贝到main.cpp并保存。#include #if defined(_MSC_VER)#include SDL.h#else#include SDL/SDL.h#endifSDL_Surface *screen;void render() / 独占资源,将surface 锁定if (SDL_MUSTLOCK(screen) if (SDL_LockSurface(screen) 0) return;/ 获取当前时间,以毫秒计时int tick = SDL_GetTicks();/ 声明变量int i, j, yofs, ofs;/ 对窗口进行绘制yofs = 0;for (i = 0; i 480; i+)for (j = 0, ofs = yofs; j pixels)ofs = i * i + j * j + tick;yofs += screen-pitch / 4;/ 解除锁定if (SDL_MUSTLOCK(screen) SDL_UnlockSurface(screen);/ 使用SDL对窗口进行更新SDL_UpdateRect(screen, 0, 0, 640, 480); / Entry pointint main(int argc, char *argv)/ 初始化SDL子系统,这里只对视频进行初始化if ( SDL_Init(SDL_INIT_VIDEO) 0 ) fprintf(stderr, Unable to init SDL: %sn, SDL_GetError();exit(1);/ 注册SDL_Quit,当退出时调用,使得退出时程序自动清理atexit(SDL_Quit);/ 使用32位象素创建640x480的窗口screen = SDL_SetVideoMode(640, 480, 32, SDL_SWSURFACE);/ 若失败,则退出if ( screen = NULL ) fprintf(stderr, Unable to set 640x480 video: %sn, SDL_GetError();exit(1);/ 主循环while (1)/ Render stuffrender();/ SDL中的事件轮询机制SDL_Event event;while (SDL_PollEvent(&event) /对消息进行处理switch (event.type) / 如果按下某键的消息响应case SDL_KEYDOWN: break;/如果某键按下后弹起的消息响应case SDL_KEYUP:/若按下ESC键,则退出if (event.key.keysym.sym = SDLK_ESCAPE)return 0;break;/退出消息响应case SDL_QUIT:return(0);return 0;对工程gp进行编译,可以看看动态水波纹的效果了:) 如图10所示。图10如果你能够看到图10中的美丽动态窗口,那么恭喜你,你可以开始漫游SDL的精彩世界了。下面我们将正式开始我们的SDL之旅。简单的象素绘制下文从使用SDL的编程函数开始,介绍了如何使用SDL在屏幕上进行象素绘制的基本知识,并给出了一个简单的例子。如果要在VC中用SDL库,必须在源文件头部包含以下头文件:#include “SDL.h”初始化SDL是通过SDL_Init()函 数来实现的。如果初始化失败,函数返回值为0。函数只接受初始化对象作为参数。如果要初始化视频屏幕,传入常数SDL_INIT_VIDEO作为参数;初 始化音频,传入常数SDL_INIT_AUDIO;如果同时初始化视频和音频,传入SDL_INIT_VIDEO|SDL_INIT_AUDIO。其它还 有一些量可以传入作为参数的(如果同时传入多个量要使用|将它们隔开):SDL_INIT_TIMERSDL_INIT_AUDIOSDL_INIT_VIDEOSDL_INIT_CDROMSDL_INIT_JOYSTICKSDL_INIT_NOPARACHUATESDL_INIT_EVENTTHREADSDL_INIT_EVERYTHING如果我们要初始化,可以使用如下语句:if ( SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO) format, R, G, B); switch (screen-format-BytesPerPixel) case 1: / Assuming 8-bpp Uint8 *bufp; bufp = (Uint8 *)screen-pixels + y*screen-pitch + x; *bufp = color; break; case 2: / Probably 15-bpp or 16-bpp Uint16 *bufp; bufp = (Uint16 *)screen-pixels + y*screen-pitch/2 + x; *bufp = color; break; case 3: / Slow 24-bpp mode, usually not used Uint8 *bufp; bufp = (Uint8 *)screen-pixels + y*screen-pitch + x * 3; if(SDL_BYTEORDER = SDL_LIL_ENDIAN) bufp0 = color;bufp1 = color 8; bufp2 = color 16; else bufp2 = color; bufp1 = color 8; bufp0 = color 16; break; case 4: / Probably 32-bpp Uint32 *bufp; bufp = (Uint32 *)screen-pixels + y*screen-pitch/4 + x; *bufp = color; break; 通过这个函数,可以传递给surface要绘制的点的(x,y)坐标和RGB值。同时,由于绘制的屏幕不能同时接受两个函数的同时操作,我们需要其他两个辅助函数,用于在绘制前对屏幕进行锁定,以及在绘制完成之后解除锁定。这两个工作 一般由SDL_MUSTLOK(SDL_Surface *screen)和SDL_UnlockSurface(SDL_Surface *screen)完成。使用如下两个自定义的函数会更加简单:void Slock(SDL_Surface *screen)if ( SDL_MUSTLOCK(screen) )if ( SDL_LockSurface(screen) 0 )return;void Sulock(SDL_Surface *screen)if ( SDL_MUSTLOCK(screen) )SDL_UnlockSurface(screen);这样,我们可以得到一个简单的主程序框架如下:#include #include #include SDL.h/ The functions are not shown to save space void DrawPixel(SDL_Surface *screen, int x, int y, Uint8 R, Uint8 G, Uint8 B); void Slock(SDL_Surface *screen); void Sulock(SDL_Surface *screen); int main(int argc, char *argv) if ( SDL_Init(SDL_INIT_AUDIO|SDL_INIT_VIDEO) 0 ) printf(Unable to init SDL: %sn, SDL_GetError(); exit(1); atexit(SDL_Quit); SDL_Surface *screen; screen=SDL_SetVideoMode(640,480,32,SDL_HWSURFACE|SDL_DOUBLEBUF); if ( screen = NULL ) printf(Unable to set 640x480 video: %sn, SDL_GetError(); exit(1); / DRAWING GOES HERE return 0; 如果对该程序进行编译运行,那么只能得到一闪而过的一个黑色的窗口。我们需要对窗口进行绘制,并且对基本的键盘鼠标事件进行处理。绘制的基本原理是,先在缓冲区绘制,再一次性将缓冲区绘制到屏幕上。这样比起一次一个象素点在屏幕上绘图的方式效率更高,速度更快,也不易出错。首先使 用循环在screen所指向的surface(缓冲区)上绘制,然后调用SDL_Flip函数将screen surface绘制到真实电脑屏幕上。SDL_Flip函数的作用是:在支持双缓冲(double-buffering)的硬件上,建立flip并返回。 硬件将等待vertical retrace,然后在下一个视频surface blit或者执行锁定返回前交换视频缓冲区。如果硬件不支持双缓冲,那么等同于调用SDL_UpdateRect(screen, 0, 0, 0, 0),即对整个screen的绘制区域进行刷新。void DrawScene(SDL_Surface *screen) Slock(screen); for(int x=0;x640;x+) for(int y=0;y480;y+) DrawPixel(screen, x,y,y/2,y/2,x/3); Sulock(screen); SDL_Flip(screen); 在SDL中对采用结构SDL_Event来描述事件,并采用轮询的机制对事件进行处理,程序中使用一个SDL_Event的实例(Instance)来检查事件的发生:SDL_Event event;轮询采用while循环来检查:while ( SDL_PollEvent(&event)if ( event.type = SDL_QUIT) /code here.if ( event.type = SDL_KEYDOWN) /code here./.事件轮询完毕之后,调用DrawScene(sreen)进行一次绘制。本例中的源代码如下:#include #include #include SDL.hvoid Slock(SDL_Surface *screen)if ( SDL_MUSTLOCK(screen) )if ( SDL_LockSurface(screen) format, R, G, B);switch (screen-format-BytesPerPixel)case 1: / Assuming 8-bppUint8 *bufp;bufp = (Uint8 *)screen-pixels + y*screen-pitch + x;*bufp = color;break;case 2: / Probably 15-bpp or 16-bppUint16 *bufp;bufp = (Uint16 *)screen-pixels + y*screen-pitch/2 + x;*bufp = color;break;case 3: / Slow 24-bpp mode, usually not usedUint8 *bufp;bufp = (Uint8 *)screen-pixels + y*screen-pitch + x * 3;if(SDL_BYTEORDER = SDL_LIL_ENDIAN)bufp0 = color;bufp1 = color 8;bufp2 = color 16; else bufp2 = color;bufp1 = color 8;bufp0 = color 16;break;case 4: / Probably 32-bppUint32 *bufp;bufp = (Uint32 *)screen-pixels + y*screen-pitch/4 + x;*bufp = color;break;void DrawScene(SDL_Surface *screen)Slock(screen);for(int x=0;x640;x+)for(int y=0;y480;y+)DrawPixel(screen, x,y,y/2,y/2,x/3);Sulock(screen);SDL_Flip(screen);int main(int argc, char *argv)if ( SDL_Init(SDL_INIT_AUDIO|SDL_INIT_VIDEO) 0 )printf(Unable to init SDL: %sn, SDL_GetError();exit(1);atexit(SDL_Quit);SDL_Surface *screen;screen=SDL_SetVideoMode(640,480,32,SDL_HWSURFACE|SDL_DOUBLEBUF);if ( screen = NULL )printf(Unable to set 640x480 video: %sn, SDL_GetError();exit(1);int done=0;while(done = 0)SDL_Event event;while ( SDL_PollEvent(&event) )if ( event.type = SDL_QUIT ) done = 1; if ( event.type = SDL_KEYDOWN )if ( event.key.keysym.sym = SDLK_ESCAPE ) done = 1; DrawScene(screen);return 0;打开和显示图片在这个例子里我们将学习如何使用SDL程序中打开和显示图片。示例程序将绘制一个漂亮的背景,上面显示一个正方形图案,并可以使用键盘的方向键移动它。如果比较熟悉“推箱子”这个游戏,可以看出这个程序实际就是推箱子游戏的基础。在程序首部包含以下头文件(stdlib.h供调用atexit()时使用):#include #include #include “SDL.h”声明3个SDL_Surface类型的全局变量,同时声明2个整型变量用于记录正方形的坐标:SDL_Surface *back;SDL_Surface *image;SDL_Surface *screen;int xpos = 0, ypos = 0;我们构造一个函数InitImage函数来打开bitmap文件(.bmp)中的图像信息,传递给SDL_Surface显示。InitImage将会 被main()函数调用。在InitImage函数中我们使用到了SDL_LoadBMP函数,它把bmp文件的文件名作为参数传入,返回指向存储图像文 件信息内存区域的指针。InitImage中我们将背景图片bg.bmp打开并使用back指针进行记录,将正方形图片image.bmp打开并使用 image指针记录。int InitImages() back = SDL_LoadBMP(bg.bmp); image = SDL_LoadBMP(image.bmp); return 0; 下面我们介绍将图像绘制到屏幕的两个函数,两个函数都被命名为DrawIMG。第一个DrawIMG函数使用SDL_BlitSurface函数来在屏幕上显示图像。在SDL中SDL_BliSurface的函数原型如下:int SDL_BlitSurface(SDL_Surface *src, SDL_Rect *srcrect, SDL_Surface *dst, SDL_Rect *dstrect);src是需要进行绘制的surface而dst是进行显示的surface。SDL_Rect是一个包含4个16位整型变量的结构:x, y, w(width)和h(height)。srcrect用来描述源surface中需要绘制部分,而dstrect用来描述在目的surface何处进行 绘制。如果设置srcrect为NULL,那么源文件中包含的整个图像都会被显示。dstrect中的x和y变量指定了在何处blit SDL_Surface src。对于dstrect来说,w(width)和h(height)这两个变量是被忽略不计的。第一个DrawIMG函数非常简单:void DrawIMG(SDL_Surface *img, int x, int y) SDL_Rect dest; dest.x = x; dest.y = y; SDL_BlitSurface(img, NULL, screen, &dest); 下面我们考虑一个复杂点的情况,如图:如果我们需要将阴影区域传递给srcrect进行绘制,我们就需要使用到srcrect结构里的几个变量了:x,y指定了所要绘制的源区域的起点坐标, 而w和h分别指定了源区域的宽度和高度。如果图中的阴影坐标起点坐标为(20,25),宽61个象素高70个象素,那么我们可以得到:srcrect中x = 20, y = 25, w = 61, h = 70。第二个DrawIMG定义如下:void DrawIMG(SDL_Surface *img, int x, int y, int w, int h, int x2, int y2) SDL_Rect dest; dest.x = x; dest.y = y; SDL_Rect dest2; dest2.x = x2; dest2.y = y2; dest2.w = w; dest2.h = h; SDL_BlitSurface(img, &dest2, screen, &dest); 绘制背景的函数DrawBG()比较简单:void DrawBG()Slock(screen);DrawIMG(back, 0, 0);Sulock(screen);绘制正方形图像的函数将会比较复杂,首先我们用背景图案填充当前正方形图像所在区域,如果不这样做的话,正方形图像的移动就会造成背景上留下黑色的方形移动轨迹,如图所示:这里,我们只填充正方形图像移动后的轨迹区域,这样比填充整个区域速度快。由于正方形区域大小是128x128,由于每次正方形只能朝某个方向移动1个 象素(pixel),为了彻底消除移动轨迹,我们背景的新填充区域扩大到132x132,这样就可以完全覆盖由于移动造成的轨迹残留。最后使用 SDL_Flip对新的图像绘制区域进行更新。函数如下:void DrawScene()Slock(screen);DrawIMG(back, xpos-2, ypos-2, 132, 132, xpos-2, ypos-2);DrawIMG(image, xpos, ypos);SDL_Flip(screen);Sulock(screen);由于要移动正方形图像,我们需要对键盘的方向键的按下事件进行响应,因此在main函数开始时定义:Uint8* keys;keys用来获得每一时间的键盘状态。获得键盘状态 的函数为SDL_GetKeyState(),它返回一个指向Uin8类型的数组头部的指针。数组的每个元素都对应记录了某个按键是否被按下的标志。这里 的实现,我们不在事件轮询SDL_PollEvent中检查按键,因为事件轮询中是只有触发事件也即SDL_PollEvent(&event) = 1才能进入循环的,因而如果我们一直按下某键不放开是不会触发新的事件发生的,要使得正方形移动我们必须一下又一下的敲击某个方向键,显示这不是我们所要 的。我们希望是按下某键不放开的话,正方形一直保持向此方向移动。因此我们将检查按键的程序段放到事件轮询之后处理。这里没有使用else if结构,因此可以多个方向键同时按下进行移动,程序段如下:int done=0;while(done = 0)SDL_Event event;while ( SDL_PollEvent(&event) )if ( event.type = SDL_QUIT ) done = 1; if ( event.type = SDL_KEYDOWN )if ( event.key.keysym.sym = SDLK_ESCAPE ) done = 1; keys = SDL_GetKeyState(NULL);if ( keysSDLK_UP ) ypos -= 1; if ( keysSDLK_DOWN ) ypos += 1; if ( keysSDLK_LEFT ) xpos -= 1; if ( keysSDLK_RIGHT ) xpos += 1; DrawScene();程序运行结果如下(我们已经将正方形图像区域移动到了窗口中央):如果想学习本程序的完整代码,可以从以下地址下载:/cgi-bin/index.pl?page =tutorials/gfxsdl/download.pl?file=lesson2.zip&blah=1以上我们简 单介绍了VC6下SDL的安装和简单应用,并举了两个小例子,当然SDL的功能远远不止这些,包括音频、定时器和线程编程等等,这里就不一一鳌数了。如果 有兴趣,SDL官方网站提供了非常详尽的函数说明、文档和使用指南,你可以在网站上获取非常多的信息。由于SDL是跨平台和开发工具的,方便游戏在各种平 台下的移植,同时还支持常用的各种开发语言。因此,有足够的理由相信,在游戏产业蓬勃发展的今天,SDL一定会得到更多开发者的青睐,用它开发出各种有趣 的游戏来。SDL(simple DirectMedia Layer)是一个可跨平台的开源库,它在Windows XP下的环境搭建方法如下。 PC:Mircrosoft Windows XP Service Pack3 Platform:Mircrosoft Visual C+ 6.0 SourceCode:SDL-devel-1.2.14-VC6.zip 步骤 1. 解压SDL-devel-1.2.14-VC6.zip.将解压后的lib文件夹里把SDL.lib SDLmain.lib拷贝到VC6.0安装目录的lib文件夹下面。 2. 将SDL.dll拷贝到系统盘的WINDOWS/SYSTEM32目录下(如果你要将之后生成的SDL应用程序转移到其他没有配置SDL环境的机器上用的话,请将SDL.dll一起拷贝)。 3. 在VC6.0安装目录的include文件夹下面新建一个SDL的目录,并将SDL-devel-1.2.14-VC6.zip解压后的include里的文件拷贝到这个SDL目录下面。 4. 打开VC6,新建一个project-win32 Application.打开project目录下面的那个setting,选中C/C+,Category里选中Code Generation,Use run-time library使用Multithread DLL. 5. 继续在上面的setting中选中Link,Category里选中input,在Object/li
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2025年无人机应用基础考试题库附答案详解
- 2025年护士执业资格考试真题及答案
- 慢性膀胱炎合并神经源性膀胱护理查房
- 阿坝藏族羌族自治州2024-2025学年八年级下学期语文月考模拟试卷
- 安徽省安庆市望江县2023-2024学年高二上学期期末考试化学考题及答案
- 2025 年小升初武汉市初一新生分班考试数学试卷(带答案解析)-(人教版)
- 2025 年小升初哈尔滨市初一新生分班考试数学试卷(带答案解析)-(人教版)
- 第一章 三角形的初步知识 过关检测试卷(含答案)2025-2026学年浙教版2024 数学八年级上册
- 资金垫付合同范本
- 源画摄影合同范本
- 中职思政试题及答案
- DB3203-T 1080-2025 城市道路路名牌设置规范
- 2025-2030量子科技前沿发展态势与中国市场投资机遇研究报告
- 设备维护方案(3篇)
- 护理操作管理课件
- 肉类加工间管理制度
- 2025年陕西、山西、青海、宁夏高考历史试卷真题(含答案解析)
- 2024-2025学年苏教版四年级下学期期末测试数学试卷(含答案)
- 动脉导管未闭封堵术的医疗护理
- 农村供水管网延伸工程可行性研究报告
- 快递公司快递员管理制度
评论
0/150
提交评论