分享
 
 
 

GFX with SDL Lesson 1: Getting started with SDL(翻译)

王朝other·作者佚名  2006-01-09
窄屏简体版  字體: |||超大  

GFX with SDL

Lesson 1: Getting started with SDL

作者:Marius Andra

翻译:heroboy

欢迎来到“GFX with SDL”的第一篇教程。

在Dev-C++中使用SDL

首先需要下载sdlDevCPP-1.2.4.zip(点击名称下载)。把zip文件解压到Dev C++的目录中,请确定include和lib文件夹(zip文件中)中的文件解压到Dev C++中的include和lib文件夹中。我计算机上的Dev-C++文件夹是c:\Dev-C++。所以解压以后,在c:\Dev-C++\lib会有libSDL.a,libSDL.la,libSDLmain.a和SDL.dll,在c:\Dev-C++\include\SDL中会有一些 .h文件。

现在,在Dev-C++中新建一个控制台工程。打开“工程属性”对话框(在“工程”菜单中)。在参数中,点击“加入库或者对象”按钮,选择libSDL.a,SDLmain.a和ligmingw32.a 三个文件。点击“确定”。

最后,在SDL项目中使用printf(…)或输出到stdout.txt中,而非屏幕。

在 Microsoft Visual C++ 6.0中使用SDL

要在MSVC6中使用SDL要下载SDL-devel-1.2.4-VC6.zip(请访问www.libsdl.org下载更新版本的SDL)。在这个压缩文件中有两个重要的文件夹-include和lib,把lib文件夹中的文件复制到MSVC6的lib文件夹中(在我的机器上是C:\Program Files\Microsoft Visual Studio\VC98\Lib),在MSVC6的include文件夹中新建一个SDL文件夹(在我的机器上是C:\Program Files\Microsoft Visual Studio\VC98\Include\SDL),把压缩文件中include文件夹中的.h文件复制到新建的文件夹中。

现在,在VC++中新建一个工程。选择“WIN32 Application”和“'an empty project”。现在要为工程创建一个cpp文件,单击File-〉new并选择 “c++ source file”,名字输入“main.cpp”。现在打开工程选项对话框(菜单project->settings)。点击“LINK”栏,添加 “sdl.lib sdlmain.lib”到连接文件中(Object/library modules)。最后,点击“C/C++”栏,在下拉菜单中选择“Code Generation”。然后在“Use run-time library”下拉框中选择“Multithreaded DLL”。

SDL.dll

SDL.dll是SDL中一个重要的文件(它在Dev-C++或MSVC6的SDL zip文件里)。如果你要运行SDL程序,你必须把SDL.dll复制到c:\windows\system (win 95, 98, ME) 或 c:\windows\system32 (on windows NT, 2000 and XP)。或者SDL.dll和你的程序在同一个文件夹。

Getting started with SDL

你已经设置好了一切。你要象下面一样在你的程序中包含 SDL/SDL.h 文件:

#include <SDL/SDL.h>

通过SDL_Init()函数初始化SDL。SDL_Init的返回值下于0表示出错。它接受一个参数,初始化的内容。SDL_INIT_VIDEO初始化视频,SDL_INIT_AUDIO初始化音频。要初始化音频和视频,使用SDL_INIT_VIDEO|SDL_INIT_AUDIO。可以初始化更多如下的项目(要同时初始化,请使用 | 分割他们):

SDL_INIT_TIMER

SDL_INIT_AUDIO

SDL_INIT_VIDEO

SDL_INIT_CDROM

SDL_INIT_JOYSTICK

SDL_INIT_NOPARACHUTE

SDL_INIT_EVENTTHREAD

SDL_INIT_EVERYTHING

因此,初始化视频和音频的代码是:

if( SDL_Init(SDL_INIT_VIDEO|SDL_INIT_AUDIO) <0 )

{

printf("Unable to init SDL: %s\n", SDL_GetError());

return 1;

}

如果出错了,SDL_GetError()函数返回一个字符串来描述这个错误。

但退出程序时,你必须调用SDL_Quit()。如果没有调用的话,可能会出现一些异常的现象。告诉编译器你要在退出时调用SDL_Quit,代码如下:

atexit(SDL_Quit);

那样就不需要在main函数中的每个return前加上SDL_Quit()了。

在SDL中需要很多的surface。一切都是surface。你可以在surface上绘图,也可以把一个surface画到另一个surface上。在SDL中,屏幕也是一个surface。在我们的程序中surface是一个指向SDL_Surface结构的指针。如下得到屏幕surface:

SDL_Surface *screen;

相信你在玩有些游戏的时候会要你选择屏幕分辨率。如果没有的话,请玩更多的游戏。如果你要使用surface屏幕(surface screen)(记住,screen只是一个指向SDL_Surface结构的指针),在上面绘图(你在监视器上可以看到画了什么),那么使用SDL_SetVideoMode()函数。

screen = SDL_SetVideoMode(640, 480, 32,

SDL_HWSURFACE|SDL_DOUBLEBUF);

前三个参数分别是屏幕的 宽度,高度和像素位数bits per pixel)。如果像素位数为0,SDL会为你自动选择最合适的位数。第四个参数是一些特殊的标记。如果要在屏幕上绘图的话,必须有SDL_HWSURFACE(或SDL_SWSURFACE)。下列是可用的选项:

SDL_SWSURFACE – 在系统内存中创建surface

SDL_HWSURFACE – 在显示内存中创建surface

SDL_ASYNCBLIT – 允许异步刷新的surface。这会降低在单CPU上的位拷贝(blitting)的速度,但在SMP系统上速度会有提升。

SDL_ANYFORMAT - 一般地,如果给与的像素位数(bits-per-pixel,bpp)不可用的话,SDL回使用影子surface(shadow surface)模拟。SDL_ANYFORMAT会阻止这么做,而忽略参数中的像素位数。

SDL_HWPALETTE –给予SDL 独立的调色板访问(exclusive palette access)。没有这个选项,你不能通过SDL_SetColors或SDL_SetPalette来获取颜色。

SDL_DOUBLEBUF –允许硬件双缓冲。只有和SDL_HWSURFACE一起使用才有效。调用SDL_Flip来翻转(flip)缓冲并刷新屏幕。所有的绘图不会立即显示在屏幕上。如果不允许双缓冲的话,SDL_Flip函数相当于对整个屏幕调用SDL_UpdateRect。

SDL_FULLSCREEN – SDL会尝试使用全屏模式。如果硬件不支持当前的分辨率的话,会使用一个更高的分辨率和黑色的背景。

SDL_OPENGL –创建OpenGL渲染上下文(rendering context)。你应该预先使用SDL_GL_SetAttribute设置OpenGL视频属性。

SDL_OPENGLBLIT -创建OpenGL渲染上下文(rendering context),但使用普通的位拷贝(blitting)操作。屏幕surface(2D)会有一个alpha通道,并且必须使用SDL_UpdateRects来更新屏幕surface。

SDL_RESIZABLE –创建可缩放的窗口。当缩放的时候,会产生SDL_VIDEORESIZE事件,此时可通过SDL_SetVideoMode再次改变屏幕surface大小。

SDL_NOFRAME - 如果可行的话,SDL会创建无框架无标题栏的窗口。全屏模式自动包含此选项。

我的建议是:使用 SDL_HWSURFACE|SDL_DOUBLEBUF。如果出错的话,使用SDL_SWSURFACE.

SDL_SetVideoMode 返回指向SDL_Surface的指针,出错的话返回NULL。使用如下代码检测出错:

if ( screen == NULL )

{

printf("Unable to set 640x480 video: %s\n", SDL_GetError());

return 1;

}

至此已经初始化了SDL,可以开始绘图了。在开始绘图前,我要告诉你一些SDL的数据类型。他们是:

Uint8 – 相当于unsigned char

Uint16 – 16位(2字节)无符号整形

Uint32 - 32位(4字节) 无符号整形

Uint64 - 64位(8字节) 无符号整形

Sint8 - 相当于 signed char

Sint16 - 16位(2字节) 有符号整形

Sint32 - 32位(4字节) 有符号整形

Sint64 - 64位(8字节) 有符号整形

另外,无论何时初始化出错的时候,你不必完全退出。例如,SDL_INIT_VIDEO初始化成功,而SDL_INIT_AUDIO失败的话,你仍然可以继续运行程序,只是没有声音。为了检测音频是否初始化成功,使用SDL_WasInit()函数。代码如下:

Uint32 init = SDL_WasInit(SDL_INIT_AUDIO);

if(init & SDL_INIT_AUDIO)

{

sound = 1; // Audio init sucessful, use sound

} else {

sound = 0; // Audio init unsucessful, don't use sound

}

你可以在如下代码中插入上述代码

if( SDL_Init(SDL_INIT_VIDEO|SDL_INIT_AUDIO) <0 )

{

printf("Unable to init SDL: %s\n", SDL_GetError());

return 1;

}

为简单起见,我不在教程中插入此代码。

绘制像素乍看是很简单的,但如果你看了此函数的话其实并不简单。我使用的这个像素绘制函数,取自SDL intro(www.libsdl.org上的)。如下:

注意:你不必完全理解它,只要使用就可以了

void DrawPixel(SDL_Surface *screen, int x, int y,

Uint8 R, Uint8 G, Uint8 B)

{

Uint32 color = SDL_MapRGB(screen->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)

{

bufp[0] = color;

bufp[1] = color >> 8;

bufp[2] = color >> 16;

} else {

bufp[2] = color;

bufp[1] = color >> 8;

bufp[0] = 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_MUSTLOCK(SDL_Surface *screen)用来确定是否需要锁定屏幕。SDL_LockSurface(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);

}

}

调用 Slock(screen)锁定屏幕, Sulock(screen)解锁。

现在,代码应该如下:

#include <stdio.h>

#include <stdlib.h>

#include <SDL/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: %s\n", 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: %s\n", SDL_GetError());

exit(1);

}

// DRAWING GOES HERE

return 0;

}

运行一下。你会发现,一个空窗口闪了一下。加入SDL_FULLSCREEN标记,会看见一个黑屏。现在,让我们绘图。

我们来做一个简单的绘图:我们把所有的东西都绘制在一个缓冲上,再把缓冲画到屏幕上。这比直接在屏幕上绘制像素简单,速度快,而且没有闪烁。

让我们在做一个彩色的屏幕(如你看见的截图)。我们通过一个循环把所有坐标绘制上去。在循环前添加锁定屏幕的函数,在循环后添加解锁的函数。Drawpixel函数在屏幕surface(缓冲)上绘制彩色的像素(每个像素颜色不同),然后使用SDL_Flip把缓冲(screen surface)绘制到实际的计算机屏幕上。

Slock(screen);

for(int x=0;x<640;x++)

{

for(int y=0;y<480;y++)

{

DrawPixel(screen, x,y,y/2,y/2,x/3);

}

}

Sulock(screen);

SDL_Flip(screen);

注意:实际上一直往屏幕上绘制像素是很慢的。通常只有在需要时,才绘制需要的某一部分。更多的请看以后的教程。

把 // DRAWING GOES HERE 替换成上述代码,并允许程序。你会看见一个彩色的窗口,但只存在很短的时间。为了存在时间长一点,添加一个循环:

for(i=0;i<100;i++)

{

Slock(screen);

for(int x=0;x<640;x++)

{

for(int y=0;y<480;y++)

{

DrawPixel(screen, x,y,y/2,y/2,x/3);

}

}

Sulock(screen);

SDL_Flip(screen);

}

循环100次,然后退出。但还有更好的方法:

我们把绘图代码放入一个函数:

void DrawScene(SDL_Surface *screen)

{

Slock(screen);

for(int x=0;x<640;x++)

{

for(int y=0;y<480;y++)

{

DrawPixel(screen, x,y,y/2,y/2,x/3);

}

}

Sulock(screen);

SDL_Flip(screen);

}

在main()函数中,我们创建一个游戏循环。游戏循环是一个循环,直至退出。我们的游戏循环是一个while循环,当done等于0时循环。

int done=0;

while(done == 0)

{

// CODE

}

在游戏循环中,我们检测是否ESC键或窗口上的X按钮被按下了。如果按下了,则令done等于1,那么循环就会结束。

一切的SDL事件使用SDL_Event结构表示。我们需要一个SDL_Event变量来检测时间:

SDL_Event event;

我们不停的获取事件(直至没有事件发生):

while ( SDL_PollEvent(&event) )

{

}

在每个 while(...) {...}中, SDL_Event 会包含事件的信息。然后我们确定事件的类型。

if ( event.type == SDL_QUIT ) { done = 1; }

if ( event.type == SDL_KEYDOWN )

{

// CODE

}

如果我们得到了退出的事件(关闭按钮被按下),我们令done等于1。如果一个按键被按下,我们在确定哪个键被按下:

if ( event.key.keysym.sym == SDLK_ESCAPE ) { done = 1; }

所有的键盘上的按键名字都以SDLK_开头。查看 SDL_keysym.h文件来得到更多的SDLK_ 键名字。事件检测之后:

DrawScene(screen);

好了,下列是全部的代码:

#include <stdio.h>

#include <stdlib.h>

#include <SDL/SDL.h>

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);

}

}

void DrawPixel(SDL_Surface *screen, int x, int y,

Uint8 R, Uint8 G, Uint8 B)

{

Uint32 color = SDL_MapRGB(screen->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)

{

bufp[0] = color;

bufp[1] = color >> 8;

bufp[2] = color >> 16;

} else {

bufp[2] = color;

bufp[1] = color >> 8;

bufp[0] = color >> 16;

}

}

break;

case 4: // Probably 32-bpp

{

Uint32 *bufp;

bufp = (Uint32 *)screen->pixels + y*screen->pitch/4 + x;

*bufp = color;

}

break;

}

}

void DrawScene(SDL_Surface *screen)

{

Slock(screen);

for(int x=0;x<640;x++)

{

for(int y=0;y<480;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: %s\n", 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: %s\n", 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;

}

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有