SDL2系列教程3-位图

时间:2024-05-30 22:28:01

位图和Blitting

你以前可能听说过位图; 可能是过时的“.bmp”图像。好吧,位图在技术上只是一种图像存储的格式,其中像素数据由一块内存表示,或者你可以说是一个位图。“bmp”格式表示在标题之后顺序存储每个像素(单色,RGB,RGBA等)的颜色值的图像。其他格式,如“png”和“jpg”仍然是位图,但利用压缩技术来减少文件大小(理想情况下),而不会牺牲图像质量。

在软件(CPU)2D渲染中,一旦将位图加载到存储器中,CPU就简单地将像素值从加载的位图修改和/或复制到表示窗口的区域。这被称为“blitting”。Blitting可能比简单地复制像素更复杂; 它也可能涉及调整大小,拉伸,翻转或以其他方式后处理图像。

SDL提供加载和blitting位图的功能。blitting API可能很有用,但它相对有限。默认情况下,SDL只能加载“bmp”格式位图 - 扩展名SDL_Image必须用于加载更多图像格式,例如“png”,“jpg”,“gif”或“tif”。我们将在第07课中了解更多扩展库。此外,在第05课中,我们将了解功能更全面的硬件(GPU)渲染API。

加载位图

上一课,我提到了SDL如何将像素内存提取到曲面。曲面可以表示加载的位图,您正在创建的新纹理,甚至是您要绘制的窗口。

要将位图加载到曲面中,请使用函数SDL_LoadBMP()。它的用法非常简单 - 只需向您发送要加载的.bmp文件的名称(相对于可执行文件的位置)。如果加载成功,您将收到一个指向包含位图数据的新SDL_Surface的指针。如果加载失败,该函数将返回NULL。

 

SDL_Surface* image = SDL_LoadBMP( "image.bmp" );

if ( !image ) {
	// load failed
}

释放曲面就像分配曲面一样简单 - 当曲面不再使用时,函数SDL_FreeSurface()可用于销毁它并释放内存。

 

SDL_FreeSurface( image );

 

保存位图

当然,加载位图的反义词是保存一个。函数SDL_SaveBMP()就是这样做的。将包含位图数据的表面和要保存的位图文件的名称传递给它。该函数将在成功时返回0或在失败时返回负值。

int result = SDL_SaveBMP( surface, "saved.bmp" );

if ( result < 0 ) {
	// save failed
}

Blitting to the Window

blit到表面的基本方法是使用SDL_BlitSurface()。该函数采用源曲面和区域,并将像素blit到目标曲面和区域。这些区域使用SDL_Rect结构指定。

源矩形包含要复制的源曲面的区域的坐标和大小。可以传递NULL而不是此矩形以使用整个表面。实际只使用目标矩形的x和y坐标,剪切将自动完成。

 

SDL_Rect dest;
dest.x = 100;
dest.y = 50;

int result = SDL_BlitSurface( surface, NULL, windowSurface, &dest );

if ( result < 0 ) {
	// blit failed
}

优化的表面

虽然不是绝对必要,但是可以相对于另一个表面优化表面以提高blits的速度。从本质上讲,这只是意味着更改曲面的像素格式以匹配另一个。然后,程序可以在blitting时简单地复制数据,而不是必须更改格式。

这是通过函数SDL_ConvertSurface()完成的。此函数采用您要转换的曲面和要转换的格式。此格式在目标曲面的“format”数据成员中指定,该成员几乎应始终为窗口曲面。如果转换成功,则该函数返回一个新的转换曲面。它不会改变或释放原始(未转换的)表面 - 你必须自己做。

SDL_Surface* load = SDL_LoadBMP("test.bmp");

SDL_Surface* image = SDL_ConvertSurface( load, windowSurface->format, 0 );

if ( !image ) {
	// convert failed
} else {
	// convert succeeded
	SDL_FreeSurface( load );
	load = NULL;
}

缩放

使用SDL_BlitSurface(),您可以在任何位置标记位图。但是,我提到只考虑目标矩形的x和y坐标。这意味着每次blitted图像的大小相同。要拉伸或缩放位图以适合任意区域,可以使用函数SDL_BlitScaled()。此函数采用与SDL_BlitSurface()相同的参数,不同之处在于它考虑了目标矩形的宽度和高度。

SDL_Rect dest;
dest.x = 100;
dest.y = 50;
dest.w = 200;
dest.h = 100;

int result = SDL_BlitScaled( surface, NULL, windowSurface, &dest );

if ( result < 0 ) {
	// blit failed
}

 

实例代码如下:


#include <iostream>
#include <SDL2/SDL.h>

using namespace std;

bool init();
void kill();
bool load();

// Variables to hold our window and surfaces
SDL_Window* window;
SDL_Surface* winSurface;
SDL_Surface* image1;
SDL_Surface* image2;

int main(int argc, char** args) {

    if ( !init() ) return 1;

    if ( !load() ) return 1;

    // Blit image to entire window
    SDL_BlitSurface( image1, NULL, winSurface, NULL );

    // Blit image to scaled portion of window
    SDL_Rect dest;
    dest.x = 160;
    dest.y = 120;
    dest.w = 320;
    dest.h = 240;
    SDL_BlitScaled( image2, NULL, winSurface, &dest );

    // Update window
    SDL_UpdateWindowSurface( window );
    SDL_Delay(5000);

    kill();
    return 0;
}

bool load() {
    // Temporary surfaces to load images into
        // This should use only 1 temp surface, but for conciseness we use two
    SDL_Surface *temp1, *temp2;

    // Load images
    temp1 = SDL_LoadBMP("test1.bmp");
    temp2 = SDL_LoadBMP("test2.bmp");

    // Make sure loads succeeded
    if ( !temp1 || !temp2 ) {
        cout << "Error loading image: " << SDL_GetError() << endl;
        return false;
    }

    // Format surfaces
    image1 = SDL_ConvertSurface( temp1, winSurface->format, 0 );
    image2 = SDL_ConvertSurface( temp2, winSurface->format, 0 );

    // Free temporary surfaces
    SDL_FreeSurface( temp1 );
    SDL_FreeSurface( temp2 );

    // Make sure format succeeded
    if ( !image1 || !image2 ) {
        cout << "Error converting surface: " << SDL_GetError() << endl;
        return false;
    }
    return true;
}

bool init() {
    // See last example for comments
    if ( SDL_Init( SDL_INIT_EVERYTHING ) < 0 ) {
        cout << "Error initializing SDL: " << SDL_GetError() << endl;
        return false;
    } 

    window = SDL_CreateWindow( "Example", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 640, 480, SDL_WINDOW_SHOWN );
    if ( !window ) {
        cout << "Error creating window: " << SDL_GetError()  << endl;
        return false;
    }

    winSurface = SDL_GetWindowSurface( window );
    if ( !winSurface ) {
        cout << "Error getting surface: " << SDL_GetError() << endl;
        return false;
    }
    return true;
}

void kill() {
    // Free images
    SDL_FreeSurface( image1 );
    SDL_FreeSurface( image2 );

    // Quit
    SDL_DestroyWindow( window );
    SDL_Quit();
}

 

Makefile如下:

SDL2系列教程3-位图

 

运行结果如下:

SDL2系列教程3-位图

 

例程下载地址:

https://download.****.net/download/cyf15238622067/10697304