随笔 - 96  文章 - 255  trackbacks - 0
<2008年2月>
272829303112
3456789
10111213141516
17181920212223
2425262728291
2345678

E-mail:zbln426@163.com QQ:85132383 长期寻找对战略游戏感兴趣的合作伙伴。

常用链接

留言簿(21)

随笔分类

随笔档案

SDL相关网站

我的个人网页

我的小游戏

资源下载

搜索

  •  

积分与排名

  • 积分 - 488849
  • 排名 - 37

最新评论

阅读排行榜

评论排行榜

作者:龙飞

2.1:准备工作。

        找一张*.bmp格式的图片。我在例子中将使用640*480大小的图片。如果你在windows下面,你可以打开画图程序自己简单的画一张,或者将其他格式的图片另存为bmp。然后将图片名字修改为helloworld.bmp(当然,你也可以在程序的相应部分修改为你目标图片的名字。),这是我们将要显示的图片。

2.2:创建一个SDL的执行窗口。

        我们讨论过,SDL是跨平台的,它的设计者希望使用SDL的源程序不要依赖于具体平台,甚至具体的GUI和窗口管理器。在前面一节中,我们已经简单使用了SDL_SetVideoMode(),在这里,我们对它做进一步的介绍——使用这个函数实际上遇到的问题会比我们预想中涉及到的问题多,换句话说,这里的介绍仍然是不完整的。我们当前的目的,只是为了简单的显示一张BMP位图。
SDL_Surface *SDL_SetVideoMode(int width, int height, int bitsperpixel, Uint32 flags);
        在这里,我们使用的flag(s)仍然是SDL_SWSURFACE。它的作用是说明所建立的surface是储存在系统内存中的。实际上,SDL_SWSURFACE是一个“伪位标”,如果你读出它的值,会发现其实是0!这意味着任何其他位标(以及|组合)与SDL_SWSURFACE的&结果都是0。这个事实的另外一层含义是,surface的数据“至少”会被储存在系统内存中——对立面的意思是,这些数据有可能储存在显存中(指定使用显存储存数据的位标是SDL_HWSURFACE,它的值是1)。
        这个函数的返回值是一个SDL_Surface的结构指针。如果返回是空指针(C中习惯用NULL,而C++标准将空指针表示为0),则表示这个函数调用失败了。我们可以通过SDL_GetError()获得异常的原因。SDL_Surface结构包含了一个surface的数据结构,包括宽,高和每个像素点的具体颜色等等,我们也放在后面具体讨论。这里,我们还是直接把SDL_Surface看成一个类,这个函数返回一个SDL_Surface类对象的指针。
        width和height是你希望建立的窗口的宽与高。如果值为0,则建立与你当前桌面等宽高的窗口。bitsperpixel是这个窗口的颜色位深。当前的硬件环境下,相信你的桌面也是32位色的。如果这个值为0,则所建立的窗口使用你当前桌面的位深。
        我们试图建立一个640*480大小的,32位色的窗口。并且让返回的surface值储存在系统内存里。(后面会介绍使用显存的方法。)需要注意的是,我们必须记下这个返回的surface的指针,因为所有的图像操作,最后都是通过修改这个surface的数据作用在显示这个surface的窗口上,最终呈现在我们眼前的。
    const int SCREEN_WIDTH = 640;    // 0 means use current width.
    const int SCREEN_HEIGHT = 480;    // 0 means use current height.
    const int SCREEN_BPP = 32;        // 0 means use current bpp.
    const Uint32 SCREEN_FLAGS = SDL_SWSURFACE;    // SDL_SWSURFACE == 0,surface in system memory.

    SDL_Surface
* pScreen = 0;
    pScreen 
= SDL_SetVideoMode(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_BPP, SCREEN_FLAGS);    // Creat a SDL window, and get the window's surface.
    try {
        
if ( pScreen == 0 )
            
throw SDL_GetError();
    }
    
catch ( const char* s ) {
        std::cerr 
<< "SDL_SetVideoMode() failed!\n" << s << std::endl;
        SDL_Quit();
        
return -1;
    }


2.3:装载BMP格式的位图。

SDL_Surface *SDL_LoadBMP(const char *file);
        这个函数使用C风格字符串的形参,这意味着如果我们使用std::string objName传值的时候,需要使用objName.c_str()(请注意objName.data()没有'/0'),把std::string类转化为C风格字符串。这个函数把一个BMP位图转化成为SDL的surface数据结构方式(SDL_Surface结构),储存在系统内存中(我没找到任何信息可以说明能直接储存到显存中),并返回这个surface的指针。如果返回的指针为空,说明函数调用失败了。
    SDL_Surface* pShownBMP = 0;
    pShownBMP 
= SDL_LoadBMP("helloworld.bmp"); // Load a BMP file, and convert it as a surface.
    try {
        
if ( pShownBMP == 0 )
            
throw SDL_GetError();
    }
    
catch ( const char* s ) {
        std::cerr 
<< "SDL_LoadBMP() failed!\n" << s << std::endl;
        SDL_Quit();
        
return -1;
    }

2.4:块移图面(blit surface)。
int SDL_BlitSurface(SDL_Surface *src, SDL_Rect *srcrect, SDL_Surface *dst, SDL_Rect *dstrect);

        src指的是要进行blit的源surface,dst指的是blit这个surface要去的目的地——另外一个surface。我们这里先忽略SDL_Rect结构的具体意思,仅仅需要了解的是,如果srcrect为空指针,意味着整个源surface将被blit;如果dstrect为空指针,意味着源surface与目的surface的左上角重合(坐标(0,0))。
        blit是个有渊源的词语,我将来会在术语解释中具体提到。这个词的本意就是块(block)移动(transfer)的缩写blt,因为这个缩写缺少元音不好读,所以后来加上了i,就变成blit。
        如果blit成功,则返回0;否则返回-1。

    SDL_Rect* pSrcRect = 0;    // If pSrcRect is NULL, the entire source surface is copied. 
 
    SDL_Rect
* pDstRect = 0;    // If pDstRect is NULL, then the destination position (upper left corner) is (0, 0).
    try {
        
if ( SDL_BlitSurface(pShownBMP, pSrcRect, pScreen, pDstRect) != 0 )    // Put the BMP's surface on the SDL window's surface.
            throw SDL_GetError();
    }
    
catch ( const char* s ) {
        std::cerr 
<< "SDL_BlitSurface() failed!\n" << s << std::endl;
        SDL_Quit();
        
return -1;
    }

2.5:显示图片。
int SDL_Flip(SDL_Surface *screen);
        源图面被blit到目的图面上后,就与目的图面融为一体了。在我们的例子中,ShownBMP被“画”在了Screen上(我这里去掉了p,是为了说明这里讨论的是surface而不是surface的指针)。换句话说,Screen被修改了(似乎也可以用“染指”-_-!!),ShownBMP则没有改变。
        另外一个需要了解的问题是,我们之前对surface的种种操作,实际上都是在修改surface数据结构中的某些数据,当我们最后需要将这些surface显示到屏幕上(我们打开的SDL操作窗口上),我们需要使用函数SDL_Flip()。如果函数调用成功,则返回0;否则返回-1。
    try {
        
if ( SDL_Flip(pScreen) != 0 )    // Show the SDL window's surface.
            throw SDL_GetError();
    }
    
catch ( const char* s ) {
        std::cerr 
<< "SDL_Flip() failed!\n" << s << std::endl;
        SDL_Quit();
        
return -1;
    }

2.6:这个例子的完整源代码。
#include <iostream>
#include 
"SDL/SDL.h"

void pressESCtoQuit();

int main(int argc, char* argv[])
{
    
try {
        
if ( SDL_Init(SDL_INIT_VIDEO) != 0 )
            
throw SDL_GetError();
    }
    
catch ( const char* s ) {
        std::cerr 
<< "SDL_Init() failed!\n" << s << std::endl;
        
return -1;
    }

    
const int SCREEN_WIDTH = 640;    // 0 means use current width.
    const int SCREEN_HEIGHT = 480;    // 0 means use current height.
    const int SCREEN_BPP = 32;        // 0 means use current bpp.
    const Uint32 SCREEN_FLAGS = SDL_SWSURFACE;    // SDL_SWSURFACE == 0,surface in system memory.

    SDL_Surface
* pScreen = 0;
    pScreen 
= SDL_SetVideoMode(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_BPP, SCREEN_FLAGS);    // Creat a SDL window, and get the window's surface.
    try {
        
if ( pScreen == 0 )
            
throw SDL_GetError();
    }
    
catch ( const char* s ) {
        std::cerr 
<< "SDL_SetVideoMode() failed!\n" << s << std::endl;
        SDL_Quit();
        
return -1;
    }

    SDL_Surface
* pShownBMP = 0;
    pShownBMP 
= SDL_LoadBMP("helloworld.bmp"); // Load a BMP file, and convert it as a surface.
    try {
        
if ( pShownBMP == 0 )
            
throw SDL_GetError();
    }
    
catch ( const char* s ) {
        std::cerr 
<< "SDL_LoadBMP() failed!\n" << s << std::endl;
        SDL_Quit();
        
return -1;
    }

    SDL_Rect
* pSrcRect = 0;    // If pSrcRect is NULL, the entire source surface is copied. 
 
    SDL_Rect
* pDstRect = 0;    // If pDstRect is NULL, then the destination position (upper left corner) is (0, 0).
    try {
        
if ( SDL_BlitSurface(pShownBMP, pSrcRect, pScreen, pDstRect) != 0 )    // Put the BMP's surface on the SDL window's surface.
            throw SDL_GetError();
    }
    
catch ( const char* s ) {
        std::cerr 
<< "SDL_BlitSurface() failed!\n" << s << std::endl;
        SDL_Quit();
        
return -1;
    }

    
try {
        
if ( SDL_Flip(pScreen) != 0 )    // Show the SDL window's surface.
            throw SDL_GetError();
    }
    
catch ( const char* s ) {
        std::cerr 
<< "SDL_Flip() failed!\n" << s << std::endl;
        SDL_Quit();
        
return -1;
    }

    pressESCtoQuit();
    SDL_Quit();

    
return 0;
}

void pressESCtoQuit()
{
    
bool gameOver = false;
    
while( gameOver == false ){
        SDL_Event gameEvent;
        
while ( SDL_PollEvent(&gameEvent) != 0 ){
            
if ( gameEvent.type == SDL_QUIT ){
                gameOver 
= true;
            }
            
if ( gameEvent.type == SDL_KEYUP ){
                
if ( gameEvent.key.keysym.sym == SDLK_ESCAPE ){
                    gameOver 
= true;
                }
            }
        }
    }
    
return;
}


2.7:补充说明。

1) 这个程序用到了前面课程中建立起来的函数pressESCtoQuit();
2) 在VC的IDE中,引用的bmp文件可能会需要提供完整的绝对路径,否则直接通过VC菜单启动的程序可能找不到实际上就与exe文件在同一个文件夹中的bmp图片。你可以直接找到编译后的exe文件,在exe文件夹中直接运行,则不会出现这个问题。或者,你可以修改VC默认的资源文件路径,再或者,你可以尊重VC的默认约定,将资源文件拷贝到工程目录下(与源文件*.cpp在同一个文件夹里面)。

posted on 2008-02-06 01:54 lf426 阅读(10261) 评论(12)  编辑 收藏 引用 所属分类: SDL入门教程

FeedBack:
# re: SDL入门教程(三):2、显示一张BMP位图。 2008-03-02 03:52 阿子
我在国外留学,老师留了一个关于用SDL实现猫的图片随鼠标移动的任务,老师已经完成了main的部分,要我们补全cat的类,并且在类中加入3个functions:

draw()this function should draw/blit the image of the cat on the surface provided through the constructor.

void tellMouse(int x, int y); – this function will store the provided coordinates as mouse position to be used in the update() function.

void update(void); – this function should update the position of the cat stored in the internal variables in such way that the cat chases the mouse.

希望大侠帮我个忙,拜谢
菜鸟阿子
  回复  更多评论
  
# 问题的解决[未登录] 2008-03-02 23:22 lf426
其他关心的朋友请参考“SDL入门教程(五):7、鼠标事件演示,代码重用 ”。  回复  更多评论
  
# re: SDL入门教程(三):2、显示一张BMP位图。 2008-04-16 15:41 WANGYY
楼主,请问一下,我按照你以上的代码运行之后图片没有显示,我已经把图片拷到跟.cpp同一个文件夹下了!但显示的是黑色的窗口!
上个教程你的回答让我很满意,谢谢楼主!  回复  更多评论
  
# re: SDL入门教程(三):2、显示一张BMP位图。[未登录] 2008-04-16 21:18 lf426
如果是没找到图片文件,会异常抛错,不会显示黑色的窗口。你说的现象,可能是其他地方有问题。  回复  更多评论
  
# re: SDL入门教程(三):2、显示一张BMP位图。 2008-04-16 21:29 WANGYY
楼主,我找到原因了,谢谢你的文章,很好哦!支持  回复  更多评论
  
# re: SDL入门教程(三):2、显示一张BMP位图。 2008-06-05 17:12 btest
不知为什么窗口没有刷新,非要将窗口最小化,再打开才会显示图片。  回复  更多评论
  
# re: SDL入门教程(三):2、显示一张BMP位图。 2008-06-06 13:29 btest
搞定了,少了一个SDL_Flip()  回复  更多评论
  
# re: SDL入门教程(三):2、显示一张BMP位图。 2008-07-16 16:40 leeken
请问使用SDL可不可同时创建和显示多个窗体(使用SDL_SetVideoMode)?我希望程序同时显示多个GUI界面。  回复  更多评论
  
# re: SDL入门教程(三):2、显示一张BMP位图。[未登录] 2008-07-16 21:14 lf426
应该是不可以。因为SDL是为游戏设计的库,这个GUI是所有键盘鼠标事件的接口。多窗口就混乱了。另外,涉及到多线程的时候也只能允许一个线程作为当前窗口来接受信号。  回复  更多评论
  
# re: SDL入门教程(三):2、显示一张BMP位图。 2009-11-05 21:44 metin9527
这个程序异常抛得真多,还不如直接在使用直接打印错误,退出程序。  回复  更多评论
  
# re: SDL入门教程(三):2、显示一张BMP位图。 2015-04-08 22:22 
先赋0给pShowBMP或pScreen,在加载图片或初始化,都会报错说此类型没有存储类或类型说明符怎么办?
还有try会说应该输入声明,怎么办?  回复  更多评论
  
# re: SDL入门教程(三):2、显示一张BMP位图。 2015-04-08 22:49 
不好意思,看到主函数了  回复  更多评论
  

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理