8.9 مكتبة SDL لبرمجة الألعاب كتاب لينكس الشامل >>

8.9 مكتبة SDL لبرمجة الألعاب

الفهرس

8.9.1 مقدمة

هي اختصار لSimple DirectMedia Layer وهي مكتبة متعددة المنصات تعمل في لينكس(إكس11) وويندوز وغيرها ، بإمكانك عمل برامج (خاصة ألعاب وبرامج متعددة الوسائط) دون الحاجة لإعادة كتابة البرنامج في كل نظام كما في allegro و glut وهي أصغر بكثير من Allegro ولكنها توفر مزايا أقل؛ فهي(SDL) توفر تحميل صور وصوت والتعامل مع الزمن وتعدد خيوط المعالجة والتعامل مع الأحداث (لوحة المفاتيح و Joystick) إلا أنها على عكس allegro لا توفر وظائف لرسم الأشكال مثل الدوائر والخطوط و المضلعات ثنائية وثلاثية الأبعاد وتحويل الصور من عمق لوني إلى آخر وخوزرميات تسريع وجداول بحث عن الألوان ومزجها والشفافية وجداول جيوب ... إلا أن SDL تسمح لك (كما allegor) بالوصول المباشر لذاكرة الصورة والكتابة فيها وعمل الوظائف التي تقوم بذلك بنفسك أو استعمال مكتبة OpenGL. انظر الوثائق التي تأتي مع حزمة التطوير /usr/share/doc/SDL-devel-1.2.4/html/

8.9.2 أساسيات SDL

لا يوجد الكثير لتتعلمه، قم بالعمليات الاستهلالية باستدعاء SDL_Init مع تمرير الأنظمة الفرعية التي تريد استعمالها وهي في العادة SDL_INIT_VIDEO|SDL_INIT_AUDIO|SDL_INIT_TIMER إذا أعطت الوظيفة قيمة سالبة فإن هناك شيئاً ما خطأ. بعدها احجز شاشة بتمرير الطول والعرض والعمق اللوني(بالبت) وخيارات أخرى للوظيفة SDL_SetVideoMode والتي تعيد مؤشر من نوع SDL_Surface أما الخيارات التي يمكنك استعمالها فهي
العلامة flagمعناها
SDL_SWSURFACEاستعمال الذاكرة العادية
SDL_HWSURFACEاستعمال ذاكرة الشاشة المسرعة، أضف الخيار SDL_DOUBLEBUF للحصول على شاشة ثنائية
SDL_FULLSCREENشاشة كاملة
SDL_RESIZABLEنافذة قابلة للتحجيم
SDL_HWPALETTEتطابق جدول الألوان الفعلي مع SDL فقط في طور 8بت
SDL_OPENGLشاشة OpenGL
SDL_OPENGLBLITشاشة OpenGL إضافة للعمليات ثنائية الأبعاد العادية
لأن SDL لا توفر جدول توقع للألوان بقوة allegro يفضل أن تستعمل عمق لوني بمقدار 16 بت أو 24 بت ، كما يفضل أن تحاول أولاً SDL_HWSURFACE|SDL_DOUBLEBUF|SDL_FULLSCREEN فإذا لم تنجح SDL_SWSURFACE مع وضع متغير يوضح أيها نجح لأن عملية تحديث الشاشة تختلف في كل منها، ففي SDL_SWSURFACE نستدع SDL_UpdateRect(screen, 0, 0, 0, 0) طبعاً يمكنك أن تحدث جزء صغير من الشاشة بتعديل قيم x و y و w و h كما في SDL_UpdateRect(screen,x,y,w,h) ، أما في الشاشة المسرعة في الحالة الأولى نستعمل SDL_Flip(screen)

#include "SDL.h"
#include <stdio.h> /* for exit() */
int main() {  
	SDL_Surface *screen;
	printf("Initializing SDL.\n");
	if((SDL_Init(SDL_INIT_VIDEO|SDL_INIT_AUDIO|SDL_INIT_TIMER)==-1)) { 
		printf("Could not initialize SDL: %s.\n", SDL_GetError());
		exit(-1);
	}
	printf("SDL initialized.\n");
	screen = SDL_SetVideoMode(640, 480, 16, SDL_SWSURFACE);
	if ( screen == NULL ) {
		fprintf(stderr,
			"Couldn't set 640x480x16 video mode: %s\n",
                        SDL_GetError());
		exit(1);
	}
	/* this to exit */
	SDL_Quit( );
	return 0;	
}
وقبل الخروج يجب أن تستدع SDL_Quit() ليقوم بتحرير الشاشة والذاكرة وكرت الصوت التي حجزها.
tipتلميح

لتصنيف البرنامج استعمال الأداة sdl-config كما يلي gcc MYFILE.C -o MYFILE `sdl-config --libs`

لتقوم بالرسم مباشرة على الشاشة(أو أي صورة أخرى) نستعمل المؤشر pixels الذي هو جزء من SDL_Surface الذي تعيده وظيفة حجز الشاشة وذلك بوضع قيمة اللون التي تحصل عليها من SDL_MapRGB(bpp,r,g,b) حيث r و g و b هي قيم بين 0 و 255 تحدد الأحمر والأخضر والأزرق و bpp هي BitPerPixel نضع هذه القيمة على بعد إزاحة معينة عن المؤشر pixels تعتمد هذه الإزاحة على كم بايت في البيكسل وكم بايت في السطر offset=(y*BytePerLine)+(x*BytePerPixel) ويمكن الحصول على كم بايت في البيكسل بقسمة BitPerPixel على ثمانية وتقريب الناتج لأقل رقم صحيح أكبر من أو يساوي الناتج Bpp=ceil(bpp). أما كم بايت في السطر فنحصل عليه من ضرب القيمة السابقة في عرض السطر الواحد أو بأخذها مباشرة من pitch . ويجب الإنتباه إلى إغلاق الصورة قبل الوصول المباشر إليها SDL_LockSurface() وإزالة الإغلاق بعد الإنتهاء منها.

بإمكانك رسم مستطيل باستعمال SDL_FillRect(surface,rect,color); حيث rect هو مؤشر إلى SDL_Rect مع وضع قيم x و y و w و h المناسبة. أما رسم الصور فعليك أولاً تحميلها بالوظيفة SDL_LoadBMP ثم نقلها/رسمها فوق صورة أخرى أو الشاشة بSDL_BlitSurface مثلاً SDL_BlitSurface(image, NULL, surface, NULL) حيث image هي الصورة المصدر و surfce هي الهدف ويمنك تحديد مكان رسمها بوضع مؤشر إلى SDL_Rect مكان NULL الثانية، فتؤخذ منه قيم x و y فقط ولتحديد الجزء الذي سيرسم من الصورة المصدر ضع SDL_Rect مكان NULL الأولى. تقوم هذه الوظيفة بعد الرسم بإعادة ضبط SDL_Rect الثانية الخاصة بالهدف لتكون القيم التي تم استعمالها فعلياً مثلاً عند رسم صورة جزء منها يخرج من الزاوية اليمنى السفلى فإن عرض وطول الصورة التي ترسم فعلياً يكون أقل.

/*
 * sdltut.c: SDL tutorial by Moayyad Al-Sadi <alsadi[at]gmail.com>
 */
#include "SDL.h"
#include <stdio.h>
#include <math.h>
/* this function draw some scratch to sraface */
void scratch(SDL_Surface *surface) {
	int x=100,y=100;
	char *file_name="./bmp/mybmp.bmp";
	SDL_Surface image;
	Uint8 *ptr;
	/* bpp=BitPerPixel , Bpp=BytePerPexil*/
	int bpp=surface->format->BitsPerPixel,Bpp=ceil(bpp/8.0);
	Uint32 c1=SDL_MapRGB(bpp,64,64,128);
	Uint32 c2=SDL_MapRGB(bpp,128,64,64);
	SDL_Rect r;
	/* load BMP file */
	image = SDL_LoadBMP(file_name);
	if (image == NULL) {
	        fprintf(stderr, "Couldn't load %s: %s\n",
			file_name, SDL_GetError());
        	return;
	}
	SDL_BlitSurface(image, NULL, surface, NULL);
	SDL_UpdateRect(surface, 0, 0, 0, 0);
	SDL_FreeSurface(image);
	/* draw rectangle */
	r.x=10; r.y=10; r.w=200; r.h=200;
	SDL_FillRect(surface,&r,c1);
	SDL_UpdateRect(surface, 0, 0, 0, 0);
	/* direct access draw line */
	SDL_LockSurface(surface);
	ptr = (Uint8 *)surface->pixels + y * surface->pitch + x * Bpp;
	switch(bpp) {
	case 1:
		for (;x<300;++x) *p++ = c2;
		break;
	case 2:
		for (;x<300;++x) *(Uint16 *)p++ = c2;
		break;
	case 4:
		for (;x<300;++x) *(Uint32 *)p++ = c2;
		break;
	}
	SDL_UnlockSurface(surface);

}
int main() {  
	SDL_Surface *screen;
	SDL_Event event;
	printf("Initializing SDL.\n");
	if((SDL_Init(SDL_INIT_VIDEO|SDL_INIT_AUDIO|SDL_INIT_TIMER)==-1)) { 
		printf("Could not initialize SDL: %s.\n", SDL_GetError());
		exit(-1);
	}
	printf("SDL initialized.\n");
	screen = SDL_SetVideoMode(640, 480, 16, SDL_SWSURFACE);
	if ( screen == NULL ) {
		fprintf(stderr,
			"Couldn't set 640x480x16 video mode: %s\n",
                        SDL_GetError());
		exit(1);
	}
	/* draw scratch on screen */
	scratch(screen);
	/* wait to exit */
	while(1) {
	while( SDL_PollEvent( &event ) ) {
	        switch( event.type ) {
		case SDL_KEYDOWN:
			if (event.key.keysym.sym==SDLK_ESCAPE) {
				SDL_Quit( ); exit(0);
			}
			break;
		case SDL_QUIT:
			SDL_Quit( ); exit(0);
            		break;
        	}
	}
	/* DO SOME THINGS HERE like move the scratch */	
	/* ... do it your self :-( */
	}

	/* never come here */
	return 0;	
}
يمكن تحميل صور من أنواع أخرى مثل PNM و XPM و XCF و PCX و GIF و JPG و TIF و PNG و LBM إضافة إلى BPM باستعمال الوظيفة IMG_load(file_name) الموجودة في إضفة لهذه المكتبة اسمها SDL_image ولا تنس إضافة السطر #include"SDL_image" في برنامجك.

8.9.3 SDL و OpenGL

عد إلى فصل openGL واتبع نفس طريقة GLUT مع استبدال وظائف GLUT ب SDL. وهي كما يلي

    SDL_GL_SetAttribute( SDL_GL_RED_SIZE, 5 );
    SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE, 6 );
    SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE, 5 );
    SDL_GL_SetAttribute( SDL_GL_DEPTH_SIZE, 16 );
    SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 );
    screen = SDL_SetVideoMode(640, 480, 16, SDL_OPENGL | SDL_FULLSCREEN);
	/* Draw things here ,the GL-way ... */
	glViewport( 0, 0, 640, 480 );
    glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
    glBegin( GL_TRIANGLE ); /* or what ever see opengl.html */

    glEnd( );
	/* update screen */
    SDL_GL_SwapBuffers();

www.ziron.com/links
http://developer.dungeon-crawl.com

<< السابق كتاب لينكس الشامل التالي >>