الفريق العربي للبرمجةأرشيف المنتديات · 2000 – 2023
نسخة أرشيفية للقراءة فقط — التسجيل والمشاركة مغلقان، والمحتوى محفوظ كما كان.

OpenGL .. الدرس رقم صفر

رائج
بدأه AlDeaj في 27 أغسطس 2004 · 19 رد · 21,362 مشاهدة · في OpenGL
مشاركة: واتساب X فيسبوك تيليجرام
#1 صاحب الموضوع

أولا وقبل كل شيء أعتذر عن التأخر في طرح الدرس ، فالدرس كان يجب ان يكون منتهي قبل 3 اسابيع ولكن لظروف صحية لم استطع انهاءه فعذرا على التأخير

مقدمة مملة ..

OpenGL .. لا أعلم لما أعشق تلك المكتبة وافضلها على Directx . أولا وكما الحال مع اي شاب طموح ( او حالم) كنت ارغب في تعلم برمجة الألعاب فكنت ابحث عن لغة برمجة (سهلة) وتلبي رغباتي في بناء حلم طفولتي بإنتاج لعبة ذات مستوى عالي ( فاينل فانتسي مثلا )  .. اتجهت إلى الفيجوال بيسيك visual basic

ولكن رأيتها لغة هشة .. بسيطة .. لاتصلح للمشاريع الكبيرة فاتجهت الى c++ .. بحثت عن دروسها كثيرا ولكن دائما ماكنت اصاب باحباط عند البرنامج الأزلي لكل لغة برمجة Hello world .. لا أعلم لماذا يراودني احساس بان هذا البرنامج بالذات هو مصدر كل احباط لكل مبرمج برغب في تعلم لغة معينة :)

رأيت بأن لغة كال C++ اذا احتجت لاتقانها لصنع لعبة ما قد يستغرق سنوات عديدة يشيب بها رأسي ويذهب قبلها حماسي فتركتها و انا اجر اذيال الخيبة .. في تلك الفترة سمعت كثيرا عن Directx وكيف ان الكثير من الألعاب وبرامج المالتي ميديا قد صنعت بها او بمساعدتها فتوجهت الى DirectX .. قمت بتنزيل الكثير من الكتب لتلك المكتبة كما قمت بشراء كتاب باللغة العربية يشرح DirectX .. لا أعرف لماذا لم اهضم تلك المكتبة ( ربما لان شرح الكتاب لم يكن جيدا) فلم أفهم منها شيئا .. بعد ان رأيت انني لا انفع للعلم :) فكرت جديا بترك البرمجة والاتجاه لاي مجال آخر .. تركت البحث لمدة سنة تقريبا وفي الفترة الاخيرة انتقلت الى نظام التشغيل لينكس linux ومن هناك تعرفت على OpenGL وعند البحث والتقصي وجدت لها عدة تطبيقات مذهلة ( ومنها ماسأقوم بشرحه بالدروس القادمة ) ولكن ما أحزنني هو عدم وجود دروس عربية لتلك المكتبة أو ربما يوجد ولكني لم أستطع الوصول اليها ، فقلت لنفسي لم لا أقوم بوضع دروس وترجمة دروس إلى اللغة العربية بما انها تفتقر الى تلك الدروس .. فتلك المكتبة سهلة الفهم وبسيطة في اوامرها عظيمة في عملها كما انني وللمرة الاولى استطعت فهم شيئا عن البرمجة .. نخيلوا ؟ :)

عند رؤيتي للدروس العربية بأي مجال كان ، تواجهني مشكلة في بعض المفردات المعربة .. فغالبا كنت لا افهم مايدور بسبب الترجمة الحرفية لمفردات معينة والتي تشتت الذهن وتضيع المعنى .. وكنت ارجع مضطرا الى البحث عن المعنى الانجليزي لتلك الكلمة لفهم الفكرة او الجملة .. لذا أثناء الدروس التي سأقوم بكتابتها او ترجمتها سوف اقوم بكتابة المفردات او الكلمات باللغة الانجليزية مع كتابة شرحها او عملها باللغة العربية .. إلى هنا تنتهي تلك المقدمة المملة . :)

درس طويل ..

هنا نبدأ بأول خطوة لنا مع OpenGL وهي أطول خطوة لنا في سلسلة دروسنا .. قد يكون الدرس طويل قليلا فسوف نقووم بكتابة كود ( طويل عريض ) من أجل انشاء نافذة فارغة .. أرى البعض قد بدأ يتذمر :) ..

قد يتسائل البعض ولما النافذة الفارغة ؟ نريد الدخول في برمجة الألعاب .. حسنا دعوني أشرح قليلا :) ..

ماسنقوم بإنشاءه الان هو الركيزة الاساسية لكل برنامج OpenGL ، فكل الدروس التالية بل كل برامج العالم المبرمجة عن طريق OpenGL تحتوي على هذا الكود فهو السطح الذي ستضع عليه كل ماستبرمجه .. عموما هذا هو اطول وأصعب درس .. ان استطعت فهمه ( وليس حفظه) فلن تواجه اية مشاكل مستقبلا ان شاء الله .. كفانا كلاما .. لنبدأ :)

أولا يجب عليك إنشاء مشروع فارغ project بواسطة Visual C++ 6.0 ويجب اختيار Win32 Application )وليس ) console application .

ثانيا يجب ربط المكتبات OpenGL libraries

بداخل Visual C++ 6.0 قم بالذهاب إلى Project ثم Settings ثم اضغط على Link الموجودة بالقائمة

تحت "Object/Library Modules" سوف تجد مجموعة من المكتبات قمت باضافة المكتبات الثلاثة التالية لهم سواء في البداية او النهاية وتأكد بوجود مسافة بين كل مكتبة واخرى

OpenGL32.lib GLu32.lib GLaux.lib

مع العلم بان تلك المكتبات تأتي مع نظام التشغيل وندوز تلقائيا

السطور الأربع الاولى من البرنامج تحتوي على الملفات الرأسية Header Files للمكتبات التي قمنا باضافتها

  #include <windows.h>  // الملف الرأسي لويندوز   Header File For Windows
#include <gl\gl.h>  // الملف الرأسي للمكتبة   OpenGL32
#include <gl\glu.h>  // الملف الرأسي للمكتبة   GLu32
#include <gl\glaux.h>  //  الملف الرأسي للمكتبة   GLaux

الآن نريد وضع جميع المتغيرات variables التي سوف نستخدمها في البرنامج .. بما اننا بصدد انشاء نافذة فارغة فقط ( لا اريد احباط ) :) فلن نستخدم الكثير من المتغيرات الآن

بالسطر الاول نقوم باعداد مايسمى بال Rendering Context ( لا اعرف ترجمته )  .. كل برنامج تقوم ببرمجته عن طريق OpenGL يحتاج Rendering Context .وهو يقوم بربط OpenGL ب Device Context الذي يقوم بعرض النافذة .. دون ان ندخل بالتفاصيل هذا مانحتاج معرفته حتى الآن .. نحتاج الى اعداد Device Context الذي يجب ربطه مع OpenGL عن طريق Rendering Context .

ال Rendering Context يعرف اختصارا hRC اي اننا اثناء البرمجة نستخدم هذا الاختصار فقط وقد قمنا بتعريفه بالسطر الأول

السطر الثاني نقوم باعداد وتهيئة Device Context وهو مايسمى اختصارا hDC

HGLRC           hRC=NULL;
HDC             hDC=NULL;  
HWND            hWnd=NULL;
HINSTANCE       hInstance

السطر الأول من الكود التالي يقوم باعداد لوحة المفاتيح Keyboard والاستجابة لاي رد فعل منه

في السطر الثاني المتغير active يستخدم لاخبار برنامجنا ان كانت النافذة قد وضعت في الخلفية بعد ان كانت بحجم كامل الشاشة او حتى بنص الشاشة .. اي اننا قمنا باخفاء النافذة minimized او انزالها حتى نقوم بتشغيل او رؤية برنامج آخر .

في السطر الثالث المتغير Full Screen واضح ولا يحتاج الى شرح ولكن سوف اقوم بشرحه :) في حال كان برنامجنا يستخدم كامل الشاشة (full screen) فان المتغير سووف يكن true واذا كان غير ذلك اي ليس بكامل الشاشة سوف يكون false

يجب وضع هذا المتغير حتى يعلم البرنامج اذا ماكنا في وضع الشاشة الكاملة ام لاوحتى يعرف كل اجراء ان كان سيطبق في وضع الشاشة الكامل ام لا

bool	keys[256];    // لتسجيل حركة لوحة المفاتيح
bool	active=TRUE;  // هذا المتغير يجب ان يكون   true 
fullscreen=TRUE;  // متغير كامل الشاشة

يجب علينا الآن تعريف WndProc() السبب في ذلك لان CreateGLWindow() يرتبط في WndProc() ولكنه يأتي بعد CreateGLWindow() .

في لغة C اذا اردنا كتابة اجراء معين او قسم معين من الكود يكون بعد الكود الذي نعمل عليه حاليا يجب علينا ان نعلن عن الاجراء اولا قبل كتابة الكود ( اقرأ هذه النقطة مرة اخرى ) 

لذا في السطر القادم سوف نقوم بتعريف WndProc() لنستطيع استخدام CreateGLWindow() .. اتفقنا ؟ سواء اتفقنا ام لا يجب علينا كتابة هذا السطر :)

LRESULT	CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

يقوم الكود التالي باعادة حجم النافذة بعد تصغيرها ( بافتراض انك لاتعمل على كامل الشاشة full screen )

GLvoid ReSizeGLScene(GLsizei width, GLsizei height)
{
	if (height==0)
	{
  height=1;
	}

	glViewport(0, 0, width, height);

في السطور التالية يتم اضافة القليل من الواقعية لمشهدنا ( على افتراض اننا نضع كائنات معينة في الشاشة)

فرؤية المشهد تتم من زاوية مقدارها 45 درجة كما هو مبين بالكود مستندة على الارتفاع والعرض للنافذة

النقاط 0.1f, 100.0f تعبر عن نقطه بداية ونقطه نهاية لمدى العمق الذي نضع به الكائنات ( سوف اشرح هذا الموضوع بتفصيل اكبر في دروس قادمة ) :)

glMatrixMode(GL_PROJECTION) يشير الى ان السطرين التاليين من الكود سوف يؤثران على مايسمى بمصفوفة التقدير

glLoadIdentity() يقوم بنفس عمل الامر reset تقريبا فهو يعيد المصفوفة المختارة الى حالتها الاولى

كل مانريد معرفته الآن ان اضافة هذا الكود تقوم بتحسين عملنا :) ( وسوف نفصل في هذا الموضوع في دروس قادمة)

glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45.0f,(GLfloat)width/(GLfloat)height,0.1f,100.0f);
glMatrixMode(GL_MODELVIEW);	
glLoadIdentity();
}

هنا نقوم بتنصيب OpenGL فيجب كتابة هذا السطر حتى نقوم باختيار الالوان ونمكن التظليل الناعم smooth shading .. الخ .

int InitGL(GLvoid)
{

بالسطر التالي نقوم بتمكين التظليل الناعم smooth shading

glShadeModel(GL_SMOOTH );

الآن نقوم بوضع الألوان .. سوف اقوم بشرح الألوان بشكل مبسط على ان نتعمق فيها لاحقا .. مدى الألوان يكون بين 0.0f و1.0f حيث ان 0.0f يكون لون داكن و 1.0f يكون لون فاتح و 0.5f يكون لون متوسط بين الداكن والفاتح .

البارامتر الأول في الكود بعد glClearColor يعبر عن اللون الأحمر والبارامتر الثاني يعبر عن اللون الأخضر والبارامتر الثالث يعبر عن اللون الأزرق والبارامتر الرابع لقيمة الفا Alpha .. لانحتاج الآن الى معرفة عمل البارامتر الفا ونكتفي بوضع قيمته صفر في الوقت الحالي .

قد يتسائل البعض لدينا 3 ألوان فقط .. الأحمر ، الأخضر والأزرق أين بقية الألوان ؟ الاجابة هي : عن طريق مزج تلك الألوان نقوم بإظهار الوان جديدة وسوف نفصل في هذا الأمر لاحقا ( يوجد الكثير من الدروس قادمة فلاتخافوا سوف نشرح كل شيء :) )

الان اذا كان لدينا glClearColor(0.0f,0.0f,1.0f,0.0f) سوف نرى ان قيمة كل من اللون الأحمر والاخضر تساوي صفر بينما قيمة اللون الأزرق تساوي واحد .. اذا سوف نحصل على اللون الازرق على الشاشة .. واذا كان لدينا glClearColor(0.5f,0.0f,0.0f,0.0f) فاننا سوف نحصل على على لون أحمر متوسط وليس احمر فاتح او احمر داكن .. وهكذا .

في الكود التالي سوف نقوم بوضع جميع القيم صفر اي اننا سوف نحصل على اللون الأسود للخلفية

glClearColor(0.0f, 0.0f, 0.0f, 0.0f);

الأسطر الثلاثة التالية لتحديد العمق في الشاشة .. مثلا لدينا كائنين على الشاشة ونريد ان نظهرهما بمظهر ثلاثي الأبعاد او ان نظهر احداهما خلف الاخر فاذا افترضنا بانه لدينا مربع ودائرة نريد عرضهما على الشاشة بحيث يكونا في بعدين مختلفين اي ان المربع بعيد والدائرة قريبه من الشاشة فمن االطبيعي ان الدائرة سوف تغطي على المربع او اجزاء منه اذا تقاطعا على خط واحد .

ومهمة الكود التالي هي توزيع الكائنات في فضاء الشاشة .. بما اننا الان نقوم بعمل شاشة فارغة فقط فاننا لانحتاج الو وضع قيم لاي كائنات ونكتفي الان بتعريفه فقط

glClearDepth(1.0f);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);

في السطر التالي نخبر OpenGL بتصحيح المنظور ليخرج لنا اداء افضل للمشهد ولو قليلا

 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);	
return TRUE;
}

القسم القادم من الكود يستدعى عندما تريد الخروج من البرنامج .. KillGLWindow() يقوم بتحرير release

كل من Rendering Context و Device Context

GLvoid KillGLWindow(GLvoid)
{

من خلال الكود التالي يجب علينا رؤية ما اذا كنا في طور الشاشة الكاملة full screen ام لا .. لماذا علينا فعل ذلك ؟ .. هل صادفت مرة اثناء خروجك من احد البرامج اختفاء بعض الايقونات من سطح المكتب وتحتاج الى عمل تحديث refresh لسطح المكتب لاستعادتها ؟ حسنا هذا السطر يقوم برؤية ما اذا كان هذا البرنامج في طور الشاشة الكاملة ام لا فاذا كان كذلك يقوم بالخروج من الشاشة الكاملة قبل اغلاق البرنامج وان كان غير ذلك ف(خير وبركة) :)

if (fullscreen)
	{

نقوم الآن باستخدامChangeDisplaySettings(NULL,0) حتى نقوم بالرجوع الى الوضع الطبيعي لسطح المكتب desktop .. اي نقوم باسترجاع القيم المخزنة في ملفات الرجستري لنظام الوندوز مثل دقة الشاشة وعمق الالوان وغيرها .. كما يقوم

ShowCursor بإظهار مؤشر الفأرةMouse Pointer

ChangeDisplaySettings(NULL,0);  
ShowCursor(TRUE);
	}

السطر التالي يقوم برؤية ان كان لدينا Rendering Context .. اذا كان غير موجودا فالبرنامج سف يقفز الى الكود الذي يقوم بالبحث عن Device Context

if (hRC)
	{

اذا كان ال Rendering Context موجودا فسوف نرى امكانية ان نقوم بتحريره release it اي نقوم بفصله عن

Device Context

if (!wglMakeCurrent(NULL,NULL))
  {

اذا لم يستطلع البرنامج تحرير hRC سوف يقوم باظهار رسالة تخبرنا بذلك

MessageBox(NULL,"Release Of DC And RC Failed.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION);
  }

نقوم الآن بمحاولة حذف delete hRC

if (!wglDeleteContext(hRC))

اذا فشلت العملية سوف تظهر رسالة تخبرنا بذلك

MessageBox(NULL,"Release Rendering Context Failed.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION);
  }
hRC=NULL;
  
	}

الآن نقوم بفحص مااذا كان لدينا Device Context ام لا وامكانية تحريره وفي حالة لم نستطع تحريره سوف تظهرر سالة تخبرنا بذلك

if (hDC && !ReleaseDC(hWnd,hDC))
{
  MessageBox(NULL,"Release Device Context Failed.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION);
hDC=NULL;
}

ونفس الامر السابق نستخدمه مع Window Handle ونرى امكانية عمل تحطيم destroy لها كما هو واضح من

DestroyWindow(hWnd) الموجود في الكود واذا فشلنا سوف تظهر رسالة تخبرنا بذلك

if (hWnd && !DestroyWindow(hWnd))	
{
MessageBox(NULL,"Could Not Release hWnd.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION);
hWnd=NULL;
}

الشئ الاخير الذي نقوم به هو عمل unregister لصنف النوافذ Windows Class حتى لاتردنا اي رسالة خطأ اثناء تشغيل البرنامج مرة اخرى واذا فشلنا تظهر لنا رسالة تخبرنا بذلك

if (!UnregisterClass("OpenGL",hInstance))
{
MessageBox(NULL,"Could Not Unregister Class.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION);
hInstance=NULL;
}
}

الآن نقوم بإنشاء نافذة OpenGL كما هو ظاهر من CreateGLWindow .. في الجزء التالي من الكود لدينا 5 بارامترات title العنوان width العرض height الطول bits البت و fullscreenflag اذا كان true يعني الشاشة كاملة وfalse يعني العكس

BOOL CreateGLWindow(char* title, int width, int height, int bits, bool fullscreenflag)
 {

عندما نريد ايجاد صيغة البكسل pixel الذي يتوافق مع عملنا سوف تقوم النافذة بتحديدها وجعلها في المتغير PixelFormat

GLuint  PixelFormat;

الآن يجب علينا عمل رجستر register لصنف النافذة window class .. يقوم صنف النافذة بتخزين معلومات النافذة التي سوف نقوم بعملها

WNDCLASS	wc;
DWORD	dwExStyle;
DWORD	dwStyle;

الاسطر الخمس التالية نقوم بتحديد موقع النافذة وسوف نفصل فيه لاحقا

RECT WindowRect;
WindowRect.left=(long)0;
WindowRect.right=(long)width;
WindowRect.top=(long)0;
WindowRect.bottom=(long)height;

الآن يجب علينا جعل المتغيران fullscreen=fullscreenflag لم افهم هذه النقطه جيدا ولماذا يجب علينا فعل ذلك ولكن يبدو اننا ان لم نفعل ذلك سوف تحدث بعض المشاكل ويكفي معرفة ذلك حتى الآن على ان نقوم بالبحث في الموضوع لاحقا

fullscreen=fullscreenflag;

الآن نقوم بتعريف define لل window class

CS_HREDRAW و CS_VREDRAW يقوم باعادة عرض النافذة عند تكبيرها او تصغيرها

CS_OWNDC يقوم بانشاء DC لنافذ تنا

WndProc هو الاجراء الذي يقوم بمراقبه الرسائل التي تظهر في البرنامج

LoadIcon يقوم بتحميل الايقونة icon

LoadCursor يقوم بتحميل مؤشر الفأرة

لم نقم باستخدام خلفية لذلك نضع wc.hbrBackground تساوي NULL

وكذلك لانريد قائمة menu فنقوم بوضع wc.lpszMenuName تساوي NULL

السطر الاخير يعبر عن اسم الصنف class name وقمنا بوضعه هنا OpenGL

hInstance  = GetModuleHandle(NULL);   wc.style                       = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
wc.lpfnWndProc  = (WNDPROC) WndProc;
wc.cbClsExtra  = 0;
wc.cbWndExtra  = 0;
wc.hInstance  = hInstance;
wc.hIcon  = LoadIcon(NULL, IDI_WINLOGO);	
wc.hCursor  = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground	= NULL;
wc.lpszMenuName  = NULL;
wc.lpszClassName	= "OpenGL";

الآن نقوم بعمل رجستر register للصنف واذا حدث اي خطأ سوف تظهر رسالة

if (!RegisterClass(&wc))
{
  MessageBox(NULL,"Failed To Register The Window Class.","ERROR",MB_OK|MB_ICONEXCLAMATION);
return FALSE;
}

الآن نسأل البرنامج ما أذا كنا بكامل الشاشة ام لا

 if (fullscreen)	
{

هذا القسم هو الخاص بالتغيير الى وضح الشاشة الكاملة .. يجب ان يكون الطول والعرض في حالة الشاشة الكاملة مثل الطول والعرض التي تنوي استدخدامها لبرنامجك ويجب ايضا ان تقوم بوضع متغيرات الشاشة الكاملة قبل انشاء نافذة البرنامج .. الآن ليس علينا الاهتمام بالطول والعرض وقيمتهما فهي سوف تحدد تلقائيا من خلال هذا الكود

DEVMODE dmScreenSettings;
memset(&dmScreenSettings,0,sizeof(dmScreenSettings));
dmScreenSettings.dmSize=sizeof(dmScreenSettings);
dmScreenSettings.dmPelsWidth	= width;
dmScreenSettings.dmPelsHeight	= height;
dmScreenSettings.dmBitsPerPel	= bits;
dmScreenSettings.dmFields=DM_BITSPERPEL|DM_PELSWIDTH|DM_PELSHEIGHT;

في الكود التالي سوف نقوم بوضع العرض والارتفاع التي نريد الانتقال اليها والتي نقوم باستيرادها من

dmScreenSettings

ChangeDisplaySettings تقوم بتغيير حجم الشاشة الى المعطيات ( الطول والعرض ) الموجودة في dmScreenSettings

if (ChangeDisplaySettings(&dmScreenSettings,CDS_FULLSCREEN)!=DISP_CHANGE_SUCCESSFUL)
{

اذا لم تتم العمليه ولم تظهر الشاشاة كاملة full screen فسوف تظهر لنا رسالة بخيارين .. اغلاق الشاشة والخروج من البرنامج او الاستمرار بدون شاشة كاملة

if (MessageBox(NULL,"The Requested Fullscreen Mode Is Not Supported By\nYour Video Card. Use Windowed Mode Instead?","NeHe GL",MB_YESNO|MB_ICONEXCLAMATION)==IDYES)

اذا اخترنا الاستمرار سوف تصبح قيمة المتغير fullscreen = false

ويستمر البرنامج في عمله

fullscreen=FALSE;
}
  	else
  	{

واذا اخترنا الخروج فسوف تظهر رسالة تخبرنا بان البرنامج سوف يغلق

القيمة false تخبر البرنامج بانه يوجد خلل في العمليه ويجب علينا الخروج

MessageBox(NULL,"Program Will Now Close.","ERROR",MB_OK|MB_ICONSTOP);
return FALSE;
  	}
  }
	}

نقوم الآن بالتأكد مره اخرى ما اذا كان وضع الشاشة الكاملة يعمل ام لا

if (fullscreen)
	{

اخفاء مؤشر الفأرة في وضعية fullscreen وان اردت اظهارها اجعل قيمتها true

dwExStyle=WS_EX_APPWINDOW;
dwStyle=WS_POPUP;
ShowCursor(FALSE);
	}
	else
	{

dwExStyle=WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;  	
  dwStyle=WS_OVERLAPPEDWINDOW;
	}

الآن نقوم بتعديل نافذة البرنامج حتى تناسب ابعاد النافذة المختارة سواء fullscreen او window type

AdjustWindowRectEx(&WindowRect, dwStyle, FALSE, dwExStyle);

نقوم بانشاء نافذتنا الآن حيث نقوم بالتمرير الى CreateWindowEx() جميع البارامترات التي يحتاجها

 if (!(hWnd=CreateWindowEx(	dwExStyle,
"OpenGL",
title,
WS_CLIPSIBLINGS |
WS_CLIPCHILDREN |
dwStyle,
0, 0,
WindowRect.right-WindowRect.left,
WindowRect.bottom-WindowRect.top,
NULL,	
NULL,
hInstance,
NULL)))

في الكود التالي سوف نقوم باختيار الالوان والبت (16 – 24 – 32 ) وغيرها من الامور التي تحتاج دروس اخرى لتفصيلها فلا تستجعلوا معرفتها الآن :)

static	PIXELFORMATDESCRIPTOR pfd=
{
sizeof(PIXELFORMATDESCRIPTOR),	
1,
PFD_DRAW_TO_WINDOW |
PFD_SUPPORT_OPENGL |
PFD_DOUBLEBUFFER,
PFD_TYPE_RGBA,	
bits,
0, 0, 0, 0, 0, 0,
0,
0,
0,
0, 0, 0, 0,
16,
0,
0,
PFD_MAIN_PLANE,	
0,
0, 0, 0	
	};

والآن مجموعة من رسائل الاخطاء -لاتحتاج الى تفصيل- والتي ستظهر لنا في حالة فشل اي عملية مع بيان سبب الخطأ

if (!(hDC=GetDC(hWnd)))
{
KillGLWindow();
MessageBox(NULL,"Can't Create A GL Device Context.","ERROR",MB_OK|MB_ICONEXCLAMATION);
return FALSE;
}
if (!(PixelFormat=ChoosePixelFormat(hDC,&pfd)))	
{
  KillGLWindow();
MessageBox(NULL,"Can't Find A Suitable PixelFormat.","ERROR",MB_OK|MB_ICONEXCLAMATION);
  return FALSE;
}
if(!SetPixelFormat(hDC,PixelFormat,&pfd))
{
  KillGLWindow();
MessageBox(NULL,"Can't Set The PixelFormat.","ERROR",MB_OK|MB_ICONEXCLAMATION);
  return FALSE;
	}	
if (!(hRC=wglCreateContext(hDC)))  
{
  KillGLWindow();
MessageBox(NULL,"Can't Activate The GL Rendering Context.","ERROR",MB_OK|MB_ICONEXCLAMATION);
  return FALSE;
}

اذا لم يحدث اي اخطاء سوف يت الانتقال الى الكود التالي والذي يعطي اولوية لظهور النافذة على الشاشة اي انه عند بدء التشغيل تكون في المقدمة حتى تراها

ShowWindow(hWnd,SW_SHOW);
SetForegroundWindow(hWnd);
SetFocus(hWnd);	
ReSizeGLScene(width, height);

InitGL() يقوم بمساعدتنا لوضع الاضاءة ، اضافة الأنسجة وغيرها

if (!InitGL())
{
KillGLWindow();
MessageBox(NULL,"Initialization Failed.","ERROR",MB_OK|MB_ICONEXCLAMATION);
  return FALSE;
	}
return TRUE;
  }

هنا يتم التعامل مع جميع الرسائل التي تظهر فعندما يتم عمل register لصنف النافذة window class تقفز مباشرة الى هذا الكود اي كيف سيتعامل البرنامج عند حدوث امور معينة

 LRESULT CALLBACK WndProc(	HWND	hWnd,	
UINT	uMsg,	
WPARAM	wParam,	
LPARAM	lParam)	
{

الآن اذا كانت قيمة uMsg هي WM_ACTIVE سوف نقوم بفحص ما اذا كانت نافذتنا في الواجهة .. ان لم تكن كذلك فالمتغير active سوف يكون false وان كانت في الواجهة فسوف يكون المتغير true

switch (uMsg)
	{

  case WM_ACTIVATE:
{
if (!HIWORD(wParam))
{
         active=TRUE
}
  	else
{
active=FALSE;
}
return 0;
  }

واذا كانت WM_SYSCOMMAND فيوجد احتمالين .. اذا كانت wParam قيمتها SC_SCREENSAVE او SC_MONITORPOWER فان حافظة الشاشة screen saver تحاول البدء او ان الشاشة سوف تدخل في طور المحافظة على الطاقة اي اعندما تغلق الشاشة بعد فترة من عدم لمس الكمبيوتر

case WM_SYSCOMMAND:
{
switch (wParam)
{
case SC_SCREENSAVE:	
case SC_MONITORPOWER:
return 0;	
}
break;
}

اما اذا كانت WM_CLOSE فسوف يغلق البرنامج

case WM_CLOSE:
{
PostQuitMessage(0);
return 0;	
}
case WM_KEYDOWN:
{
keys[wParam] = TRUE;	
return 0;
}
case WM_KEYUP:
{
keys[wParam] = FALSE;
return 0;	
}
case WM_SIZE:
{
ReSizeGLScene(LOWORD(lParam),HIWORD(lParam));
return 0;
}
}
return DefWindowProc(hWnd,uMsg,wParam,lParam);
int WINAPI WinMain(	HINSTANCE	hInstance,
HINSTANCE	hPrevInstance,
LPSTR  lpCmdLine,
int  nCmdShow)
{
MSG	msg;
BOOL	done=FALSE

القسم التالي من الكود يخبرك عند تشغيل البرنامج اذا ماكنت تريد تشغيله بكامل الشاشة ام لا

if (MessageBox(NULL,"Would You Like To Run In Fullscreen Mode?", "Start FullScreen?",MB_YESNO|MB_ICONQUESTION)==IDNO)
	{
fullscreen=FALSE;	
}

الكود التالي لانشاء نافذة OpenGL مع الكتابة في أعلى البرنامج title وهنا مكتوب NeHe's OpenGL Framework وتستطيع كتابة اي جملة اخرى مكانها

if (!CreateGLWindow("NeHe's OpenGL Framework",640,480,16,fullscreen))
{
return 0;	
	}
while(!done)

	{

والان نقوم بالتأكد اذا ماكانت هناك رسائل ترد الى البرنامج لتطبيقها وجعل البرنامج يتعامل معها

if (PeekMessage(&msg,NULL,0,0,PM_REMOVE))
{
if (msg.message==WM_QUIT)
{
done=TRUE;
}
  	else
{
TranslateMessage(&msg);

DispatchMessage(&msg);
}
  }
  else
  {

وان لم تكن هناك اي رسائل خطأ سوف تعرض شاشتنا

في السطر الاول نرى ان كانت نافذتنا في الواجهة ام لا

وفي السطر الثاني نخبر البرنامج انه عند الضغط على الزر Esc يجب عليه الخروج من البرنامج

if (active)

{
	if (keys[VK_ESCAPE])
{
  done=TRUE;
}
    else
{

DrawGLScene();	
SwapBuffers(hDC);
}
  	}

السطر التالي يجعلنا قادرين على الخروج من طور الشاشة الكاملة والعودة الى الوضع التالي عن طريق الضغط على الزر f1

if (keys[VK_F1])
{
keys[VK_F1]=FALSE;
KillGLWindow();	
fullscreen=!fullscreen;
if (!CreateGLWindow("NeHe's OpenGL Framework",640,480,16,fullscreen))
{
return 0;
}
  	}
  }
	}

نهاية سعيدة ..

انتهى درسنا الأول ولله الحمد .. وهو طويل جدا كما ترون .. الدروس التالية سوف تكون قصيرة بإذن الله وجميلة وممتعة في نفس الوقت

الملف المصدري لهذا الدرس على هذا العنوان

http://nehe.gamedev.net/data/lessons/vc/lesson01.zip

الدرس الأصلي موجود في هذا الموقع لمن أراد الاطلاع عليه

http://nehe.gamedev.net/data/lessons/lesson.asp?lesson=01

اخيرا انتظر الاستفسارات او انتظر احد الاخوة الذي يقول لي بانه مستعد للدرس الثاني ومستعد لبدء الدرس الثاني في اي وقت ولو من اجل شخص واحد

لي رجاء خاص .. عند نقل الموضوع لأي منتدى آخر يرجى ذكر المصدر .. فقد تعبت كثيرا في اعداد الدرس وترجمته

اسألكم الدعاء ..

لكم تحياتي وتقديري

علي الدعيج

رابط الدرس التالي :

الدرس رقم 1

تم تعديل هذه المشاركة بواسطة HGB في 5 سبتمبر 2004 في 17:44

3

برمجة الجرافيكس والألعاب والوسائط المتعددة

=====================================

لقد توفي اخيكم على الدعيج ثالث ايام عيد الفطر 1425 ... ادعو له بالرحمه والمغفره ... إدارة المنتدى .

=====================================

#2

ماشاء الله عليك اخي مبدع اللهم لا حسد :)

بارك الله فيك استمر اخي الكريم

نحتاج مثل هذه الدروس

لكن توجد عندي ملاحظه بسيطه

انت تشرح بعدين تضع الكود وليس العكس :)

اختر الي يناسبك

استمر ولا تبخل علينا بارك الله فيك

#3

السلام عليكم ,,

والله مبدع من أفضل المقدمات التي قرأتها على الاطلاق ,, والترجمة مع لمساتك السحرية جعلت الموضوع رائع جدا ,,

ولي طلب واحد لو سمحت ,,

هو أن تستمر حتى لو لم يكمل معك بعض الافراد ,, فسيصبح الموضوع في يوم من الايام مرجع محترم باللغة العربية لمن يريد أن يكمل المشوار ,,

الله يبارك فيك ويعافيك ,,

وأنا سأقرا معك أول بأول :)

لأن كنت أريد أن أتعلم ال OpenGL ,, لكن كنت كسلان أبدأ لوحدي وأترك ال directX ,,

banner_60_468.gif

NOTHING IS IMPOSSIBLE

#5

شكرا على ردودكم التي افرحتني كثيرا

وشكرا للاخوة ال 38 الذين دخلوا الى الموضوع (حتى وقت كتابتي لهذا الرد) واتمنى ان يكونوا قد استفادوا من هذا الدرس

أخي Celeron

الشرح اول بعدين الكود

الكود اول بعدين الشرح

مو مهم .. المهم في كود مشروح :)

ولكن بما انك اول من يرد على موضوعي فلك ماتريد

من الدرس القادم الكود وبعدين الشرح :)

شكرا على مرورك وتكرمك بالرد

استاذي HGB

اخجلتني كثيرا بردك

وصفي بكلمة مبدع ومنك انت شخصيا وسام كبير اعتز به استاذي

استمرار الدروس شيء مؤكد بإذن الله مالم يطرأ امر خارج عن ارادتي يمنعني عن ذلك

اما بخصوص عدم اكمال بعض الافراد ومتابعتهم للدروس فهذت شيء طبيعي وكنت اتوقعه حتى قبل كتابة الدروس

كون OpenGL

ليست معروفة لدى الكثيرين خاصة محبي تكنولوجيا مايكروسوفت والمتعصبين لها :)

رد الاعضاء على دروسي ومتابعتهم لها شرف كبير لي واتمناه كثيرا

ولكن تأكد ان الدروس لن تتعطل بسبب عدم التفاعل

فأنا على ثقة بقدوم اليوم الذي سيستفيد منه شخص ما من تلك الدروس

ألم يحصلك معك يوما عند البحث في المواضيع القديمة رؤية بعض الدروس الجميله وعند الاندماج بها تجد بان صاحبها قد توقف عنها بسبب عدم التفاعل ؟ حصلت معي كثيرا وكم كنت اتمنى ان اكون موجودا في تلك الايام لاتفاعل مع كاتب الدرس حتى لايوقف دروسه

لا اريد ان يتكرر هذا الموقف مستقبلا مع دروسي .. لن يتكرر بإذن الله

عذرا على الاطالة .. فأنا وللأسف كثير الكلام :)

برمجة الجرافيكس والألعاب والوسائط المتعددة

=====================================

لقد توفي اخيكم على الدعيج ثالث ايام عيد الفطر 1425 ... ادعو له بالرحمه والمغفره ... إدارة المنتدى .

=====================================

#6
anwarica كتب:
والله مجهود رائع يا أخى

رغم اننى متحيز لD3D ولكن شرحك رائع وجزاك الله خيرا :)

شكرا على مرورك وردك أخي الكريم

يبدو ان ردك قد جاء اثناء كتابتي لردي :)

انا ايضا احب D3D

لكن ارى بانها تحتاج انسان على وزن عالم ذرة حتى يتعلمها :)

لك تحياتي وتقديري

برمجة الجرافيكس والألعاب والوسائط المتعددة

=====================================

لقد توفي اخيكم على الدعيج ثالث ايام عيد الفطر 1425 ... ادعو له بالرحمه والمغفره ... إدارة المنتدى .

=====================================

#7
اقتباس
انا ايضا احب D3D

لكن ارى بانها تحتاج انسان على وزن عالم ذرة حتى يتعلمها

على رأى المثل عندنا "مفيش حلاوة من غير نار" :)

فى نيتى نقل الموضوع ولكن قبل ذلك أرجو تحديد شروط نقله (فلم أفهم معنى المصدر هل المنتدى أم الموقع الدرس نفسه أم كلاهما)

#8

السلام عليكم ,,

لابأس فالنعمل على التوازي ,, وناقشنا سابقا محاسن ومساويء كل من ال Direct3D وال OpenGL ,, ويمكن أن نقول أن ال direct3D ليست لضعاف القلوب فهي متعبة أكثر من ال OpenGL ,, لكن مع الطريقة التي سنتبعها ان شاء الله في التعلم الجماعي سيصبح الموضوع أسهل ,,

الله يخليك يا AlDeaj ويعافيك :)

banner_60_468.gif

NOTHING IS IMPOSSIBLE

#9

أخي anwarica

المصدر الذي اعنيه هو الموضوع الذي في هذا المنتدى :)

وليس الموضوع الاصلي باللغة الانجليزية

اذا كان المكان الذي تريد نقل الموضوع اليه لايسمح بوضع روابط لمنتديات اخرى فلا تضع المصدر ويكفي الاشارة الى انه منقول

شكرا على مرورك وتكرمك بالرد

لك تحياتي وتقديري :)

استاذي HGB

اعجبتني جمله "ليست لضعاف القلوب" :) هي فعلا كذلك

شكرا على مرورك وتكرمك بالرد

لك تحياتي وتقديري

:)

تم تعديل هذه المشاركة بواسطة AlDeaj في 30 أغسطس 2004 في 00:09

برمجة الجرافيكس والألعاب والوسائط المتعددة

=====================================

لقد توفي اخيكم على الدعيج ثالث ايام عيد الفطر 1425 ... ادعو له بالرحمه والمغفره ... إدارة المنتدى .

=====================================

#10

لي طلب يا AlDeaj ,, لو استطعت ضع كل الدروس في رابط واحد وسيكون ذلك أفل ,, ربما ستفعل ذلك فعلا ,, لكن عنوان الموضوع الحالي يدل على أنك ستضع كل درس في موضوع مستقل ,,

المهم لو وضعت كل الدروس في رابط واحد سيكون ذلك أفضل لأن المواضيع قد تضيع ويصعب الوصول اليها ,, وفي النهاية الأمر عائد اليك فأنت صاحب الموضوع ,,

banner_60_468.gif

NOTHING IS IMPOSSIBLE

#11

استاذي الكريم

أرى ( ومن الممكن ان اكون مخطئا) بان وضع كل درس في موضوع أفضل

اليك الاسباب

أولا : عندما يريد أحد الاشخاص مستقبلا رؤية أحد الدروس أو رؤية موضوع معين في OpenGL فانه سوف يذهب مباشرة إلى ذلك الموضوع او ذلك الدرس ويرى مايريد بينما اذا كانت الدرووس كلها في مكان واحد ولنفرض اننا وصلنا الى الدرس العاشر مع 100 رد في الموضوع فانه سوف يتعب حتى يتمكن من الوصول الى الدرس او النقطه التي يريد معرفتها بعكس الموضوع المستقل فانه سوف يجد مايريد دون الاضطرار الى البحث بين اكثر من 100 رد ليجد ضالته

ثانيا :عند وصولنا مثلا الى احد الدروس المتقدمة واراد احد الاشخاص بدء تعلم OpenGL فمن الطبيعي بان اسئلته سوف تكون حول الدروس الاولى بينما تجد بقية الاشخاص في الدروس المتقدمة ولو اختلطت الاسئله المتقدمة بالابتدائية لضاع الاعضاء المتقدمين و المبتدئين بسبب تشابك الاسئله وكثرة الردود التي تعني كل منها بدرس معين فلذلك ارى ان يكون لكل درس موضوع نقاش يختص به فقط

ثالثا : ليس لدي ماقوله ولكن بما ان كل موضوع يحتوي على اولا وثانيا يجب ان يحتوي على ثالثا قمت بكتابة ثالثا :)

اخيرا استاذي تلك الدروس لكم وتمت كتابتها من اجلكم فإن أردتموها في موضوع واحد لكم ذلك وان شئتم جعلتها منفصله فاختاروا مايناسبكم وانا على استعداد لعمل مايريحكم

لك تحياتي وتقديري

:)

برمجة الجرافيكس والألعاب والوسائط المتعددة

=====================================

لقد توفي اخيكم على الدعيج ثالث ايام عيد الفطر 1425 ... ادعو له بالرحمه والمغفره ... إدارة المنتدى .

=====================================

#12

بعد اذن أخونا وأستاذنا HGB ، اتفق مع الأخ AlDeaj حيث اننى ذقت الويل من تجميع مواضيع واحدة للشرح وكان مصيرها الاختفاء دون الاستفادة منها رغم الجهد المبذول (مثال: موضوع احتراف النت مثل البحث المتقدم فى قسم الدعم الفنى ومواقع الانترنت) ولو اننى قدمت كل موضوع على حده لكان افضل بكثير .. :)

#13

السلام عليكم ,,

طيب تمام السبب فعلا منطقي ,, لكن ضع رابط للدرس التالي في كل نهاية درس في اول موضوع ,, ليسهل التنقل بين الدروس ,,

ويمكن أن تكون صفحة في النهاية للتنقل بين الدروس ,,

وأنا في نهاية الدروس سأجمعها في مكان منفصل في موضوع واحد أيضا ,, لكن في النهاية بعد أن ننتهي ,,

واستمر حاليا بوضع الدروس كل على حدة ,,

والله يعينك ,, وفي انتظار التالي :)

banner_60_468.gif

NOTHING IS IMPOSSIBLE

#14

ربنا يباركلك على هذا المجهود

لكن لى مشكله انا نقلت الكواد كلها ولم تعمل

حملت الأكواد من الموقع لم تعمل

علما بأن الملف التنفيذى عمل جيدا

الأكواد عندما اضغط ctrl+f7 لايوجد اخطاء

عندما اضغط ctrl+f5 يظهر 16 خطأ

ماذا افعل :(

163374357.gif

#15
اقتباس
أدعو لأخيكم AlDeaj بالرحمة فلقد توفي ثالث أيام العيد ... رحمه الله

اذا اردت اي اسئلة اخي فاطرحها في موضوع اخر ..

رحم الله موتى المسلمين .. اللهم امين ..

logo1.png تطبيق طمأنينة ، نسخة بيتا على أندرويد

عبدالله الشمّري - Al-Shammari

CodingAlone.com

twitter @abshammeri

abshammeri AT gmail.com

github : abshammeri

#16

ألله يرحمك ويحسن اليك

بجد شرح رائع

:)

#17

الله يرحمه و يسكنه فيسح جناته و يغفر له آمين.

tvquran_6.gif

#18

بســم الله الـرحمــن الرحيــم

رحمة الله عليك وإن شاء الله تكون في ميزان حسناتك إن شاء الله

وتعتبر صدقة جارية بأذن الله

#19

الله يرحمه ويجعل مثواه الجنة

هذا الموضوع بإذن الله يعتبر صدقة جارية

ملاحظة : هل يمكن اعادة رفع السورس كود كامل :happy:

#20

السلام عليكم , علي الدعيج رحمه الله كان يأخذ الدروس من موقع HEHE ستجد الشيفرة البرمجية لكل درس من دروس NEHE و لكل بئية تشغيل

أتظر على Legacy Tutorials .

تم تعديل هذه المشاركة بواسطة 3ds max2010 في 28 أغسطس 2012 في 14:19

تخيل, هل سيكون مستقبل الأوبن جي أل مع البشرية هكذا

future.jpg

مواضيع مشابهة