2.1:準備工作。
找一張*.bmp格式的圖片。我在例子中將使用640*480大小的圖片。如果你在windows下面,你可以打開畫圖程序自己簡單的畫一張,或者將其他格式的圖片另存爲bmp。然後將圖片名字修改爲helloworld.bmp(當然,你也可以在程序的相應部分修改爲你目標圖片的名字。),這是我們將要顯示的圖片。
2.2:創建一個SDL的執行窗口。
我們討論過,SDL是跨平臺的,它的設計者希望使用SDL的源程序不要依賴於具體平臺,甚至具體的GUI和窗口管理器。在前面一節中,我們已經簡單使用了SDL_SetVideoMode(),在這裏,我們對它做進一步的介紹——使用這個函數實際上遇到的問題會比我們預想中涉及到的問題多,換句話說,這裏的介紹仍然是不完整的。我們當前的目的,只是爲了簡單的顯示一張BMP位圖。
這個函數的返回值是一個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_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格式的位圖。
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)。
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* 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:顯示圖片。
另外一個需要了解的問題是,我們之前對surface的種種操作,實際上都是在修改surface數據結構中的某些數據,當我們最後需要將這些surface顯示到屏幕上(我們打開的SDL操作窗口上),我們需要使用函數SDL_Flip()。如果函數調用成功,則返回0;否則返回-1。
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 "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在同一個文件夾裏面)。