第2章.圖和影像

目錄
對SDL_Video的介紹
和SDL在一起使用OpenGL

對SDL影像的介紹

影像大概是SDL最普遍使用的東西,和它是最完整的子系統.這裡是一些演示基本例子.

起始Video Display

這個幾乎是所有的SDL程式都會使用的.

例子2-1.起始Video Display

var    
    screen_ : PSDL_Surface;
begin
    //起始SDL程式庫
    if ( SDL_Init(SDL_INIT_VIDEO) < 0 ) then
    begin
        MessageBox(0, PChar(Format('Couldn''t initialize SDL : %s',
          [SDL_GetError])), 'Error', MB_OK or MB_ICONHAND);
        //在離開前清除
        SDL_Quit;
exit;
end;

(*
*預置在一640x480 8位palettized方式中展示
*請求一軟體表面
*)
screen_:=SDL_SetVideoMode((640,480,8,SDL_SWSURFACE);
if(screen_=nil)then
begin

        MessageBox(0, PChar(Format('Couldn''t set 840x480x8 video mode : %s',
          [SDL_GetError])), 'Error', MB_OK or MB_ICONHAND);
        SDL_Quit;
exit;
end;
end;

設定最好的影像方式

如果你偏愛某些映像點深度但是可以接受任何其他的,在下面請使用SDL_ANYFORMAT和SDL_SetVideoMode.你也能使用SDL_VideoModeOK()為native影像方式找到那個是最接近你請求的影像方式.

例子2-2.最好的影像方式

    //偏愛8位但是接受任何深度
    screen_ := SDL_SetVideoMode(640, 480, 8, SDL_SWSURFACE or SDL_ANYFORMAT);
    if ( screen_ = nil ) then
    begin
        MessageBox(0, PChar(Format('Couldn''t set 640x480x8 video mode : %s',
          [SDL_GetError])), 'Error', MB_OK or MB_ICONHAND);
        SDL_Quit;
halt(1);
end;
    MessageBox(0, PChar(Format('Set 640x480 at %d bits-per-pixel mode',
          [screen_.format.BitsPerPixel])), 'Error', MB_OK or MB_ICONHAND);

裝載和展示一BMP檔案

一旦SDL 被起始和特定的影像方式被設定,下列的函式(function)就可以裝載和展示出BMP檔案.

例子2-3.裝載和展示一BMP檔案

procedure display_bmp( file_name : PChar );
var
  image : PSDL_Surface;
begin
    //把BMP檔案裝入一表面
    image := SDL_LoadBMP(file_name);
    if ( image = nil ) then
    begin
        MessageBox(0, PChar(Format('Couldn''t load %s : %s',
          [file_name, SDL_GetError])), 'Error', MB_OK or MB_ICONHAND);
exit;
end;

(*
*Palettized銀幕方式將有一塊預設的調色盤(一個標準
*8*8*4彩色的方塊),但是如果影像也是palettized,我們可以
*為一更好的彩色使用那塊調色盤相配
*)
if (image.format.palette and screen_.format.palette) then
begin
SDL_SetColors(screen_, @image.format.palette.colors[0], 0, image.format.palette.ncolors);
end;

//Blit 到銀幕表面上面
if (SDL_BlitSurface(image, nil, screen_, nil) < 0) then
MessageBox(0, PChar(Format('BlitSurface error : %s', [SDL_GetError])), 'Error', MB_OK or MB_ICONHAND);

SDL_UpdateRect(screen_, 0, 0, image.w, image.h);

//釋放分配到的BMP影像表面
SDL_FreeSurface(image);
end;

直接在影像平面繪圖

下列的二個函式(function)過去經常使用作取得和設定(get and set)特定影像表面的特定的影像點.他們是特別設計用作支持任何現時在SDL支持的影像深度.請記得在呼叫之前,鎖上該影像平面和在呼叫出任何其它SDL功能之前,鬆開它.

在轉變映像點數值和他們的紅色,綠色,blue成分時,請用SDL_GetRGB(和SDL_MapRGB).

例子2-4.getpixel()

(*
 *取回映像點數值在(x,y)
 *筆記:在呼叫這個之前,影像表面一定要鎖住!
 *)
function getpixel( surface : PSDL_Surface; x : integer; y : integer ) : Uint32;
type
  TByteArray = array[0..2] of Byte;
  PByteArray = ^TByteArray;
var
   bpp : integer;
   p : PInteger;
begin
   bpp := surface.format.BytesPerPixel;
   //這裡p向我們想要找回的映像點是地址
   p := Pointer(Uint32(surface_.pixels) + y * surface_.pitch + x * bpp);


   case bpp of 
      1:
        result := LongWord(p^);

      2:
        result := PUint16(p)^;

      3:
        if (SDL_BYTEORDER = SDL_BIG_ENDIAN) then
            result := PByteArray(p)[0] shl 16 or PByteArray(p)[1] shl 8 or PByteArray(p)[2]
        else
            result := PByteArray(p)[0] or PByteArray(p)[1] shl 8 or PByteArray(p)[2] shl 16;

      4:
        result := PUint32(p)^;

   else
        result := 0;       // shouldn't happen, but avoids warnings
   end;
end;

例子2-5.putpixel

 (*
 *設定映像點(x,y)成一特定的數值
 *筆記:在呼叫這個之前,影像表面一定要鎖住!
 *)
function getpixel( surface : PSDL_Surface; x : integer; y : integer ) : Uint32;
type
  TByteArray = array[0..2] of Byte;
  PByteArray = ^TByteArray;
var
   bpp : integer;
   p : PInteger;
begin
   bpp := surface.format.BytesPerPixel;
   //這裡p是我們想要設定的映像點的地址
    p := Pointer(Uint32(surface_.pixels) + y * surface_.pitch + x * bpp);


   case bpp of 
      1:
        result := LongWord(p^);

      2:
        result := PUint16(p)^;

      3:
        if (SDL_BYTEORDER = SDL_BIG_ENDIAN) then
            result := PByteArray(p)[0] shl 16 or PByteArray(p)[1] shl 8 or PByteArray(p)[2]
        else
            result := PByteArray(p)[0] or PByteArray(p)[1] shl 8 or PByteArray(p)[2] shl 16;

      4:
        result := PUint32(p)^;

   else
        result := 0;       // shouldn't happen, but avoids warnings
   end;
end;
下列的代碼使用putpixel在上方運轉把一黃色映像點嵌入screen_的中部.

例子2-6.使用putpixel

    //程式在銀幕的中心部署一黃色映像點
var
    x, y : integer;
    yellow : Uint32;
begin
    (*把彩色的黃色映射到這展示(R:=$ff,G:=$FF,B:=$00)
       筆記:如果展示是palettized,你必須首先設定調色盤.
    *)
    yellow := SDL_MapRGB(screen_.format, $ff, $ff, $00);

    x := screen_.w div 2;
    y := screen_.h div 2;

    //使銀幕鎖上,以直接傳取映像點
    if ( SDL_MustLock(screen_) ) then
    begin
        if ( SDL_LockSurface(screen_) < 0 ) then
        begin
            MessageBox(0, PChar(Format('Can''t lock screen : %s', [SDL_GetError])), 'Error', MB_OK or MB_ICONHAND);
exit;
end;
end;

putpixel(screen_, x, y, yellow);

if ( SDL_MustLock(screen_) > 0 ) then
begin
SDL_UnlockSurface(screen_);
end;
//更新我們已經改變的部份
SDL_UpdateRect(screen_, x, y, 1, 1);
end;