SDL - Simple DirectMedia Layer
http://www.libsdl.org/
SDL - бесплатный кроссплатформенный мультимедийный программный интерфейс. Как следует из названия, функции SDL оперируют структурами, максимально приближенными к аппаратному обеспечению мультимедиа-средств, что позволяет существенно повысить производительность приложений, использующих мультимедиа (игры, медиа-плееры и т. п.)
Интерфес SDL делится на несколько подсистем: видео, события (клавиатура
и мышь), звук, CD-ROM аудио, таймеры, нити (threads). Видео-подсистема SDL
предоставляет возможность использования видеорежима с любой глубиной цвета
(от 8 бит и выше), при необходимости используя преобразование, если режим
не поддерживается аппаратно; обеспечивает прямой доступ в линейный графический
видеобуфер; позволяет работать с атрибутами прозрачности или альфа-сопряжения
(alpha blending); использует аппаратное ускорение для операций копирования,
заполнение и преобразования (например, оптимизация под MMX на x86).
При компиляции программ на Си, использующих SDL, компилятору необходимо
передавать дополнительную опцию -lSDL:
gcc sdlex.c -lSDL |
Перед использованием функций SDL следует инициализировать библиотеку
при помощи функции SDL_Init, ее параметр - битовое поле, отражающее,
какие подсистемы SDL приложение собирается задействовать. Для вычисления этого
параметра удобно использовать константы SDL_INIT_AUDIO, SDL_INIT_VIDEO,
SDL_INIT_CDROM, SDL_INIT_TIMER, которые, при необходимости, объединяются
побитовым "ИЛИ". Для выгрузки библиотеки и освобождения ресурсов по окончанию
работы используется процедура SDL_Quit. Если в процессе работы
с библиотекой возникает ошибка, то ее текстовое описание можно получить при
помощи SDL_GetError.
uses SDL; function SDL_Init(flags:Uint32):integer; procedure SDL_Quit; function SDL_GetError:PChar; | #include <SDL/SDL.h> int SDL_Init(Uint32 flags); void SDL_Quit(void); char *SDL_GetError(void); |
Во FreePascal процедуры и функциии каждой подсистемы объявлены в отдельных модулях, поэтому, кроме модуля SDL, необходимо подключать еще и модули используемых подсистем (например, SDL_Video, SDL_Audio,...) | В Си в зависимости от версии и платформы, возможно, потребуется подключить заголовочные файлы подсистем SDL ("SDL_video.h", "SDL_audio.h",...), если это не делается в основном файле "SDL.h". |
Видео-подсистема SDL оперирует структурами SDL_Surface ("поверхность"). Поверхность представляет область "графической" памяти, кодирующей изображение. Эта структура содержит следующие поля:
- flags - битовое поле, характеризующее свойства поверхности: SDL_SWSURFACE (буфер в системной памяти), SDL_HWSURFACE (буфер в видеопамяти), SDL_ASYNCBLIT (асинхронные операции), SDL_FULLSCREEN (полноэкранный режим), SDL_OPENGL (поверхность контекста OpenGL), SDL_HWACCEL (использовать аппаратное ускорение) и др.
- format - указатель на структуру SDL_PixelFormat, описывающую формат кодирования цвета пикселов (наиболее полезное поле в этой структуре - BytesPerPixel - количество байт, отводимых под пиксел в графическом буфере поверхности.
- w, h - размеры изображения (в пикселах).
- pitch - размер (в байтах) одной строки пикселов изображения.
- pixels - указатель на графический буфер поверхности.
function SDL_SetVideoMode(width,height:integer; bpp:integer; flags:Uint32):PSDL_Surface; function SDL_GetVideoSurface:PSDL_Surface; |
SDL_Surface *SDL_SetVideoMode(int width, int height, int bpp, Uint32 flags); SDL_Surface *SDL_GetVideoSurface(void); |
Кроме дисплейной поверхности (связанной с видеобуфером) программа может
оперировать неотображаемыми поверхностями. Создать пустую неотображаемую
поверхность можно при помощи функций SDL_CreateRGBSurface и (непустую)
SDL_CreateRGBSurfaceFrom. Можно также создать поверхность и заполнить
ее изображение из графического файла в формате BMP. Кроме того, SDL поддерживает
сохрание изображения поверхности в BMP-файле. Для копирования изображения между
поверхностями можно использовать SDL_BlitSurface. Параметры SDL_Rect
задают положение и размер копируемых областей. В случае дисплейной поверхности,
чтобы изменения вступили в силу, надо обновить отображаемую область при помощи
SDL_UpdateRect или SDL_UpdateRects. Если вы копируете
изображение на дисплейную поверхность, для ускорения копирования можно
предварительно конвертировать исходную поверхность в формат дисплейной
поверхности - SDL_DisplayFormat. Для конвертирования поверхности
в произвольный формат предназначена функция SDL_ConvertSurface.
При завершении работы необходимо освободить память от каждой из неотображаемых
поверхностей при помощи процедуры SDL_FreeSurface.
function SDL_LoadBMP(file:PChar):PSDL_Surface; function SDL_SaveBMP(surface:PSDL_Surface; file:PChar):integer; function SDL_BlitSurface(src:PSDL_Surface; srcrect:PSDL_Rect; dst:PSDL_Surface; dstrect:PSDL_Rect):integer; procedure SDL_UpdateRect(screen:PSDL_Surface; x,y:Sint32; w,h:Sint32); procedure SDL_UpdateRects(screen:PSDL_Surface; numrects:integer; var rects:SDL_RectArray); function SDL_DisplayFormat(surface:PSDL_Surface):PSDL_Surface; procedure SDL_FreeSurface(surface:PSDL_Surface); |
SDL_Surface *SDL_LoadBMP(const char *file); int SDL_SaveBMP(SDL_Surface *surface, const char *file); int SDL_BlitSurface(SDL_Surface *src, SDL_Rect *srcrect, SDL_Surface *dst, SDL_Rect *dstrect); void SDL_UpdateRect(SDL_Surface *screen, Sint32 x, Sint32 y, Sint32 w, Sint32 h); void SDL_UpdateRects(SDL_Surface *screen, int numrects, SDL_Rect *rects); SDL_Surface *SDL_DisplayFormat(SDL_Surface *surface); void SDL_FreeSurface(SDL_Surface *surface); |
Приведенная ниже программа загружает из файла картинку в
BMP-формате и отображает ее в разных местах дисплейной поверхности.
program gr1; uses SDL, SDL_Video; var screen,img:PSDL_Surface; r:SDL_Rect; i:integer; begin if SDL_Init(SDL_INIT_VIDEO)<>0 then begin writeln('SDL_Init failed: ',SDL_GetError); halt(1); end; screen:=SDL_SetVideoMode(640,480,32,SDL_SWSURFACE); if screen=nil then begin writeln('SDL mode failed: ',SDL_GetError); halt(1); end; img:=SDL_LoadBMP('img_ex.bmp'); if img=nil then begin writeln('Picture is not available!'); halt(2); end; r.w:=img^.w; r.h:=img^.h; SDL_SetColorKey(img,SDL_SRCCOLORKEY, SDL_MapRGB(img^.format,179,217,255)); for i:=0 to 20 do begin r.x:=i*20; r.y:=i*20; SDL_BlitSurface(img,nil,screen,@r); end; SDL_UpdateRect(screen,0,0,640,480); readln; SDL_FreeSurface(img); SDL_Quit; end. | #include <stdio.h> #include <SDL/SDL.h> #include <SDL/SDL_video.h> SDL_Surface *screen,*img; SDL_Rect r; int i; int main() { if (SDL_Init(SDL_INIT_VIDEO)) { fprintf(stderr,"SDL_Init failed: %s\n",SDL_GetError()); return 1; } screen=SDL_SetVideoMode(640,480,32,SDL_SWSURFACE); if (!screen) { fprintf(stderr,"SDL mode failed: %s\n",SDL_GetError()); return 1; } img=SDL_LoadBMP("img_ex.bmp"); if (!img) { fprintf(stderr,"Picture is not available!\n"); return 2; } r.w=img->w; r.h=img->h; SDL_SetColorKey(img,SDL_SRCCOLORKEY, SDL_MapRGB(img->format,179,217,255)); for (i=0; i<400; i+=20) { r.x=r.y=i; SDL_BlitSurface(img,NULL,screen,&r); } SDL_UpdateRect(screen,0,0,640,480); getchar(); SDL_FreeSurface(img); SDL_Quit(); } |
В данной программе используется функция SDL_SetColorKey, которая
позволяет задать ключевой цвет (цвет, соответствующий прозрачному). Ключевой
цвет (параметр key) задается в формате кодирования цвета для данной поверхности.
Для преобразования цвета из RGB-компонент в заданный формат кодирования удобно
использовать функцию SDL_MapRGB. Формат кодирования обычно задается
полем format структуры SDL_Surface. Данная функция возвращает цвет пиксела в
формате поверхности. Следует иметь в виду, что при записи в видеобуфер надо
использовать лишь SDL_PixelFormat->BitsPerPixel бит данного значения,
игнорируя старшие биты, в противном случае может быть испорчена информация
о цвете для последующих пикселов.
function SDL_SetColorKey(surface:PSDL_Surface; flag:Uint32; key:Uint32):integer; function SDL_MapRGB(fmt:PSDL_PixelFormat; r,g,b:Uint8):Uint32; |
int SDL_SetColorKey(SDL_Surface *surface, Uint32 flag, Uint32 key); Uint32 SDL_MapRGB(SDL_PixelFormat *fmt, Uint8 r, Uint8 g, Uint8 b); |
Для построения произвольных изображений необходимо непосредственно обращаться
к видеопамяти поверхности (по адресу pixels структуры SDL_Surface).
Перед изменением буфера необходимо заблокировать поверхность
при помощи SDL_LockSurface, а когда изменения закончены -
разблокировать (SDL_UnlockSurface). Между операциями блокирования /
разблокирования не следует выполнять никаких системных или библиотечных вызовов.
function SDL_LockSurface(surface:PSDL_Surface):integer; procedure SDL_UnlockSurface(surface:PSDL_Surface); |
int SDL_LockSurface(SDL_Surface *surface); void SDL_UnlockSurface(SDL_Surface *surface); |
Приведенная ниже программа строит три вложенных окружности разного цвета.
В примере приводится процедура putpixel, пригодная для режимов с глубиной
цвета 32 бита.
program gr1; uses SDL,SDL_Types,SDL_Video; type parr=array [0..1] of byte; var screen:PSDL_Surface; x,y:real; const t:real=0; procedure putpixel(s:PSDL_Surface; x,y:integer; r,g,b:Uint8); var ptr:^Uint32; begin ptr:=addr(parr(s^.pixels^) [s^.pitch*y+s^.format^.BytesPerPixel*x]); ptr^:=SDL_MapRGB(s^.format,r,g,b); end; begin if SDL_Init(SDL_INIT_VIDEO)<>0 then begin writeln('SDL_Init failed: ',SDL_GetError); halt(1); end; screen:=SDL_SetVideoMode(640,480,32,SDL_SWSURFACE); if screen=nil then begin writeln('SDL mode failed: ',SDL_GetError); halt(1); end; SDL_WM_SetCaption('circles',nil); SDL_LockSurface(screen); while t<2*3.1416 do begin x:=20*cos(t); y:=20*sin(t); putpixel(screen,round(x+320),round(y+200),255,0,0); putpixel(screen,round(2*x+320),round(2*y+200),0,255,0); putpixel(screen,round(3*x+320),round(3*y+200),0,0,255); t:=t+0.0001; end; SDL_UnlockSurface(screen); SDL_UpdateRect(screen,0,0,640,480); readln; SDL_Quit; end. | #include <stdio.h> #include <math.h> #include <SDL/SDL.h> #include <SDL/SDL_video.h> SDL_Surface *screen; float t=0,x,y; void putpixel(SDL_Surface *s, int x, int y, Uint8 r, Uint8 g, Uint8 b) { void *ptr=(char*)(s->pixels)+ s->pitch*y+s->format->BytesPerPixel*x; *(Uint32*)ptr=SDL_MapRGB(s->format,r,g,b); } int main() { if (SDL_Init(SDL_INIT_VIDEO)) { fprintf(stderr,"SDL_Init failed: %s\n",SDL_GetError()); return 1; } screen=SDL_SetVideoMode(640,480,32,SDL_SWSURFACE); if (!screen) { fprintf(stderr,"SDL mode failed: %s\n",SDL_GetError()); return 1; } SDL_WM_SetCaption("circles",NULL); SDL_LockSurface(screen); while (t<2*3.1416) { x=20*cos(t); y=20*sin(t); putpixel(screen,x+320,y+200,255,0,0); putpixel(screen,2*x+320,2*y+200,0,255,0); putpixel(screen,3*x+320,3*y+200,0,0,255); t+=0.0001; } SDL_UnlockSurface(screen); SDL_UpdateRect(screen,0,0,640,480); getchar(); SDL_Quit(); } |
SDL предоставляет небольшой набор функций управления оконным интерфейсом:
SDL_WM_SetCaption - изменить заголовок окна,
SDL_WM_GetCaption - получить заголовок окна,
SDL_WM_ToggleFullScreen - переключиться из оконного режима
в полноэкранный и обратно и некоторые другие.
procedure SDL_WM_SetCaption(title,icon:PChar); procedure SDL_WM_GetCaption(var title,icon:PChar); function SDL_WM_ToggleFullScreen(surface:PSDL_Surface):integer; |
void SDL_WM_SetCaption(const char *title, const char *icon); void SDL_WM_GetCaption(char **title, char **icon); int SDL_WM_ToggleFullScreen(SDL_Surface *surface); |