أولا وقبل كل شيء أعتذر عن التأخر في طرح الدرس ، فالدرس كان يجب ان يكون منتهي قبل 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
HGLRC hRC=NULL;HDC hDC=NULL; HWND hWnd=NULL;HINSTANCE hInstance
bool keys[256]; // لتسجيل حركة لوحة المفاتيحbool active=TRUE; // هذا المتغير يجب ان يكون true fullscreen=TRUE; // متغير كامل الشاشة
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
GLvoid ReSizeGLScene(GLsizei width, GLsizei height){ if (height==0) { height=1; } glViewport(0, 0, width, height);
glMatrixMode(GL_PROJECTION);glLoadIdentity();gluPerspective(45.0f,(GLfloat)width/(GLfloat)height,0.1f,100.0f);glMatrixMode(GL_MODELVIEW); glLoadIdentity();}
int InitGL(GLvoid){
glShadeModel(GL_SMOOTH );
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClearDepth(1.0f);glEnable(GL_DEPTH_TEST);glDepthFunc(GL_LEQUAL);
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); return TRUE;}
GLvoid KillGLWindow(GLvoid){
if (fullscreen) {
ChangeDisplaySettings(NULL,0); ShowCursor(TRUE); }
if (hRC) {
if (!wglMakeCurrent(NULL,NULL)) {
MessageBox(NULL,"Release Of DC And RC Failed.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION); }
if (!wglDeleteContext(hRC))
MessageBox(NULL,"Release Rendering Context Failed.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION); }hRC=NULL; }
if (hDC && !ReleaseDC(hWnd,hDC)){ MessageBox(NULL,"Release Device Context Failed.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION);hDC=NULL;}
if (hWnd && !DestroyWindow(hWnd)) {MessageBox(NULL,"Could Not Release hWnd.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION);hWnd=NULL;}
if (!UnregisterClass("OpenGL",hInstance)){MessageBox(NULL,"Could Not Unregister Class.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION);hInstance=NULL;}}
BOOL CreateGLWindow(char* title, int width, int height, int bits, bool fullscreenflag) {
GLuint PixelFormat;
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;
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";
if (!RegisterClass(&wc)){ MessageBox(NULL,"Failed To Register The Window Class.","ERROR",MB_OK|MB_ICONEXCLAMATION);return FALSE;}
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;
if (ChangeDisplaySettings(&dmScreenSettings,CDS_FULLSCREEN)!=DISP_CHANGE_SUCCESSFUL){
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;} else {
MessageBox(NULL,"Program Will Now Close.","ERROR",MB_OK|MB_ICONSTOP);return FALSE; } } }
dwExStyle=WS_EX_APPWINDOW;dwStyle=WS_POPUP;ShowCursor(FALSE); } else {dwExStyle=WS_EX_APPWINDOW | WS_EX_WINDOWEDGE; dwStyle=WS_OVERLAPPEDWINDOW; }
AdjustWindowRectEx(&WindowRect, dwStyle, FALSE, dwExStyle);
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)))
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);
if (!InitGL()){KillGLWindow();MessageBox(NULL,"Initialization Failed.","ERROR",MB_OK|MB_ICONEXCLAMATION); return FALSE; }return TRUE; }
LRESULT CALLBACK WndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
switch (uMsg) { case WM_ACTIVATE:{if (!HIWORD(wParam)){ active=TRUE} else{active=FALSE;}return 0; }
case WM_SYSCOMMAND:{switch (wParam){case SC_SCREENSAVE: case SC_MONITORPOWER:return 0; }break;}
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; }
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 {
if (active){ if (keys[VK_ESCAPE]){ done=TRUE;} else{DrawGLScene(); SwapBuffers(hDC);} }
if (keys[VK_F1]){keys[VK_F1]=FALSE;KillGLWindow(); fullscreen=!fullscreen;if (!CreateGLWindow("NeHe's OpenGL Framework",640,480,16,fullscreen)){return 0;} } } }