به راهنماي OpenGL خوش آمديد . همانطور که در صفحه فهرست هم گفته شد اين راهنما بر پايه NeHe Production بنا شده و در حقيقت بيشتر يک ترجمه آزاد است که متن برنامه ها به دلفي برگردانده شده است و هر جا که لازم ديده ام مطالبي را به آن افزوده ام . و اما دليل اين امر اين بود که خود من هر چه گشتم راهنماي فارسي براي اين موضوع پيدا نکردم . ( هر چند ترجمه ها به فارسي افتضاح است . ولي براي شروع بد نيست ) به همين دليل تصميم گرفتم که راهنماي NeHe را به فارسي برگردانم تا سايرين مشگل من را نداشته باشند . از پاراگراف زير ترجمه اين متن شروع مي شود که در حقيقت از پاراگراف چهارم درس يک NeHe مي باشد .

من اين راهنما را با کد نويسي شروع مي کنم . اولين چيزي که شما لازم داريد ساختن يک پروژه جديد در دلفي است . اگر نمي دانيد چطور اينکار را بايد انجام دهيد لازم است ابتدا دلفي را ياد بگيريد . به خاطر داشته باشيد که ما ( حداقل فعلا ) نيازي به فرم نداريم و با همان فايل dpr کار خواهيم کرد . پس فرم را از پروژه برداريد .

 
   

 

program lesson1;

 

   
 

4 خط زير چيزهايي است که برنامه درس اول ما براي اجرا نياز دارد .

 
   

 

uses

  Windows,                                                       // بخش ويندوز ( براي تعاريف متغيرها )

  Messages,                                                      // بخش پيغامها ( براي بخش چک کردن وضعيت برنامه )

  OpenGL;                                                        // OpenGL بخش اصلي  

 

   
 

حالا ما بايد متغيرهايي را که برنامه مان به آنها نياز دارد را تعريف کنيم . اين برنامه يک صفحه خالي مي سازد . پس ما نيازي به تنظيم متغيرهاي زيادي نداريم . ولي همين چند متغيري که در پايين مي بينيد بسيار با اهميت هستند و در تمام برنامه هايي که ما مي نويسيم استفاده خواهند شد . خط دوم يک متغير براي Rendering Context تعريف مي کند .  ( مترجم متن !؟! ) . هر برنامه مبتني بر OpenGLبه يک متغير از نوع مترجم متن ( Rendering Context )متصل مي شود . يک Rendering Context تمام مراجعات OpenGL را به يک Device Contextمتصل مي کند . ما اين متغير را h_Rc مي ناميم . براي اينکه برنامه ما در يک پنجره ( window )تمام عمليات ترسيم ( draw )خود را انجام مي دهد ما نياز به يک متغير Device Context داريم که در خط سوم آنرا تعريف کرده ايم . اين متغير h_Dc ناميده شده است . DCپنجره (window) را به GDIيا همان رابط گرافيکي ( Graphics Device Interface) متصل مي کند . RCبخش OpenGLرا به DC متصل مي کند .

در خط چهارم متغير h_Wnd دستگيره (handle) ي را که ويندوز به پنجره ما اختصاص داده است نگه مي دارد .

 
   

 

var

  h_Rc: HGLRC;                                  // Permanent Rendering Context

  h_Dc: HDC;                        // Private GDI Device Context

  h_Wnd:HWND;                       // Holds Our Window Handle

 

   
 

اولين خط يک آرايه براي نگهداري دکمه هاي فشرده شده بر روي صفحه کليد تعريف مي کند . راههاي زيادي براي اينکه بفهميم چه دکمه هايي از صفحه کليد فشار داده شده اند وجود دارد . ولي راهي که من انجام مي دهم اين است . اين راه قابل اطمينان بوده و همينطور قابليت نگهداري فشرده شدن همزمان چند دکمه را نيز دارد ( يعني اگر در زماني که مشغول انجام کاري هستيم و قابليت آن را نداريم که همان لحظه کار مورد نظر را انجام دهيم مي توانيم کليدها را نگه داشته و سر فرصت يکي يکي پردازش مورد نظر را انجام دهيم ) .متغير activeبراي اين بدرد مي خورد که ببينيم آيا برنامه ما کوچک ( minimize ) شده و به قسمت task bar رفته يا اينکه فعال است . اگر کوچک شده است ما مي توانيم کارهايي براي معوق گذاردن عمليات انجام دهيم که با خروج از برنامه متفاوت است . من اين کار را ترجيح مي دهم زيرا باعث مي شود که برنامه ما در background اجرا نشود . ( در بازيهاي معروف و حتي غير معروف هم اگر با Alt+Tab به صفحه ويندوز برگرديد مشاهده مي کنيد که برنامه suspend شده و عملا از cpu استفاده نمي کند )  متغير FullScreen< هم که واضح است . اگر برنامه در حالت تمام صفحه باشد اين متغير درست (true) بوده و در غير اينصورت نادرست . اين متغير بايد به صورت عمومي (global) باشد تا تمام روالها و زير برنامه ها از اين موضوع مطلع شوند .

 
   

 

  keys: array [0..255] of BOOL;                       // Array Used For The Keyboard Routine

  Active:bool;                                                    // Window Active Flag

  FullScreen:bool;                                              // Fullscreen Flag

 

   
 

کار اين روال اين است که اگر شما در حالتي غير از تمام صفحه (fullscreen) اندازه پنجره را تغيير دهيد چشم انداز OpenGL را تغيير دهد . اگر شما در حالت تمام صفحه هم باشيد اين روال حداقل يکبار در ابتداي کار صدا زده خواهد شد تا نماي پرسپکتيو ما را تنظيم کند . چشم انداز يا نماي OpenGL ما به اندازه پنجره اي خواهد بود که در آن نمايش داده مي شود .

 
   

 

procedure ReSizeGLScene(Width: GLsizei; Height: GLsizei);                 //Resize And Initialze The GL Window

var

  fWidth, fHeight: GLfloat;

begin

  if (Height=0) then                                                                                // Prevent A Divide By Zero If The Window Is Too Small

     Height:=1;                                                                                       // By Making The Height One

  glViewport(0, 0, Width, Height);                                                         // Reset The Current Viewport And Perspective Transformation

 

   
 

خطوط زير صفحه را براي يک نمايش پرسپکتيو تنظيم مي کنند ( دو خط اول به دليل اينست که دلفي و در حقيقت پاسکال از خاصيت تغيير اتوماتيک نوع متغيرها برخلاف سي C برخوردار نيست ) . اجسام فاصله دار کوچک تر خواهند بود . اين کار يک منظره واقعي تر رسم مي کند . پرسپکتيو با يک زاويه 45 درجه که بر پايه طول و عرض صفحه بنا مي شود محاسبه خواهد شد . مختصات 0.1 و 100  (100و0.1) نقطه شروع و نقطه پايان آخرين عمقي است که ما در صفحه مي توانيم رسم کنيم . glMatrixMode(GL_PROJECTION)مشخص مي کند که دو دستور بعدي براي OpenGLبر روي ماتريس ترسيم Projection Matrix ) تاثير مي گذارند . اين ماتريس مسئول اضافه کردن حالت پرسپکتيو به خروجي تصوير ماست . glLoadIdentity() مانند حالت ريست است . و ماتريس مشخص شده را به حالت اصلي (original) خود مي برد . بعد از صدا زدن glLoadIdentity() ما مقادير خودمان را براي ساختن نماي پرسپکتيو تنظيم مي کنيم . glLoadIdentity()مشخص مي کند که تمام تغييرات جديد بر روي ماتريس مدل نمايش (modelview matrix) تاثير مي گذارند .اين ماتريس جايي است که اطلاعات اشياء(object) ما نگهداري مي شوند . در نهايت ما اين ماتريس را ريست مي کنيم . اگر چيزي را اينجا متوجه نشديد زياد هم نگران نباشيد زيرا من آنها را در ساير بخشها دوباره توضيح خواهم داد . فعلاً اينقدر بدانيد که اين اعمال براي اينکه منظره پرسپکتيو خوبي داشته باشيد لازم است .

 
   

 

  fWidth := width;

  fHeight := height;

  glMatrixMode(GL_PROJECTION);       // Select The Projection Matrix

  glLoadIdentity();                  // Reset The Projection Matrix

  gluPerspective(45.0,fWidth/fHeight,0.1,100.0);// Calculate The Aspect Ratio Of The Window

  glMatrixMode(GL_MODELVIEW);        // Select The Modelview Matrix

  glLoadIdentity                     //Reset The Modelview Matrix

end;

 

   
 

در اين قسمت ما تمام اقدامهايي را که براي تنظيم OpenGL لازم است انجام خواهيم داد . ما رنگي را براي پاک کردن صفحه تنظيم مي کنيم بافر لازم براي عمق بخشي به کارمان را مشخص مي کنيم روش smooth shading را فعال مي کنيم و ...  اين بخش صدا زده نخواهد شد مگر زماني که صفحه OpenGL ساخته شده باشد . اين تابع مقداري را برمي گرداند که به دليل اينکه فعلا بخش ارزش دهي آغازين (initialization) ما چندان پيچيده نيست از آن صرف نظر مي کنيم .

 
   

 

function InitGL:bool;     // All Setup For OpenGL Goes Here

begin

 

   
 

خط زير حالت smooth shading را فعال مي کند . اين حالت باعث مي شود که رنگهاي دور يک چند ضلعي زيبا تر به نظر برسند و خطوط صاف روشن تر بنظر برسند . راجع به اين حالت بعدا بيشتر صحبت خواهيم کرد .

 
   

 

  glShadeModel(GL_SMOOTH);                                    // Enables Smooth Color Shading

 

   
 

خط زير رنگي را مشخص مي کند که صفحه با آن پاک خواهد شد . اگر نمي دانيد که ترکيب رنگها چگونه است ، من آنرا شرح مي دهم . محدوده عددي رنگها از صفر تا يک تغيير مي کند . اين عدد بصورت مميز دار است . صفر به معني تيره ترين و يک به معني روشن ترين است . اولين پارامتر بعد از glClearColor رنگ قرمز است . دومي براي سبز و سومي براي آبي ( قرمزته !!! ) . بالاترين عدد يک است بمعني روشن ترين . آخرين عدد مقدار آلفا ناميده مي شود که در هنگام تنظيم رنگ براي پاک کردن صفحه بکار نمي رود . فعلا با مقدار آن کاري نداريم . بعداً آنرا توضيح خواهم داد . شما مي توانيد با ترکيب رنگها از سه رنگ اصلي رنگ جديدي بسازيد . مثلاً glClearColor(0.0f,0.0f,1.0f,0.0f) صفحه را با رنگ آبي روشن پاک مي کند . و glClearColor(0.5f,0.0f,0.0f,0.0f) صفحه را با رنگ قرمز متوسط پاک مي کند . نه روشن ( يک ) و نه پررنگ ( صفر ) براي يک پس زمينه سفيد شما بايد تمام رنگها را به بالاترين حد ممکن يعني يک تنظيم کنيد . و براي مشکي به کمترين حد ممکن يعني صفر .

 
   

 

  glClearColor(0.0, 0.0, 0.0, 0.5);                        // Black Background

 

   
 

سه خط بعدي براي تنظيم بافر عمق بکار مي روند . بافر عمق را مانند لايه ها در نظر بگيريد . اين بافر مشخص مي کند که اشياء روي صفحه چه عمقي دارند . ما در اين مثال از اين بافر استفاده نخواهيم کرد ولي هر برنامه OpenGLکه بر روي صفحه اشياء سه بعدي رسم مي کند از اين بافر استفاده مي کند . اين بافر ترتيب کشيده شدن اشياء را بر روي صفحه مشخص مي کند که به عنوان مثال دايره جلوتر است يا مربع و گوشه هاي مربع بايد مشخص باشد يا نه . اين بافر يکي از پر اهميت ترين بخشهاي OpenGL است .

 
   

 

  glClearDepth(1.0);                                            // Depth Buffer Setup

  glEnable(GL_DEPTH_TEST);                                       // Enables Depth Testing

  glDepthFunc(GL_LESS);                                              // The Type Of Depth Test To Do

 

   
 

در خط زير ما به OpenGL مي گوييم که بهترين تصحيح سازي را براي پرسپکتيو مي خواهيم . اينکار سرعت عملکرد (performance) ما را کمي پايين مي آورد ولي نتيجه تصويري بهتري را به ارمغان مي آورد .

 
   

 

  glHint(GL_PERSPECTIVE_CORRECTION_HINT,GL_NICEST);//Realy Nice perspective calculations

 

   
 

در نهايت مقدار درست  (true) را بر مي گردانيم تا اگر خواستيم در بخش مقدار دهي اوليه آنرا چک کنيم بتوايم . ما در اين مثال جايي را براي خطا نداشتيم ولي شما مي توانيد اين بخش را به برنامه خود اضافه کنيد . فعلا اين بخش براي ما اهميتي ندارد .

 
   

 

  initGL:=true;                                    // Everything went fine

end;

 

   
 

اين بخش شامل تمام چيزهايي مي شود که شما مي خواهيد بر روي صفحه رسم کنيد . هر چيزي که مي خواهيد برروي صفحه رسم کنيد در اين بخش از کد قرار مي گيرد . هر درس بعد از اين درس بخش و يا بخشهايي را به اين قسمت اضافه مي کند . اگر از OpenGL سر در مي آوريد ( و يا آورديد ) مي توانيد اشياء مورد نظر خود را بعد از glLoadIdentity() و قبل از Result:=true; رسم کنيد . ولي اگر تازه OpenGL را شروع کرده ايد تا درس بعدي صبر کنيد . الان ما صفحه را با رنگي که قبلا مشخص کرده بوديم پاک مي کنيم ، بافر عمق و منظره را نيز پاک مي کنيم . ما اينجا چيزي رسم نمي کنيم .
وقتي مقدار درست (true) را بر مي گردانيم برنامه مي فهمد که اشکالي رخ نداده است . اگر مي خواهيد که برنامه در اثر بروز خطا کار ديگري انجام دهد بعد از beginيک
Result := False; اضافه کنيد .

 
   

 

function DrawGLScene():bool;    // Here's Where We Do All The Drawing

begin

  glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT); // Clear The Screen And The Depth Buffer

  glLoadIdentity();                 // Reset The View

  Result:=true;            // Everything Went OK

end;

 

   
 

اين بخش از برنامه قبل از خروج از برنامه يکبار صدا زده مي شود . کار KillGLWindow() اين است که Rendering Contextو Device Context و در نهايت هندل صفحه را آزاد کند . اگر در هر مرحله اي برنامه نتواند يکي از اين کارها را انجام دهد با يک پيغام اين خطا را به شما اعلام مي کند تا ايراد يابي راحت تر انجام گيرد .

 
   

 

procedure KillGLWindow; //Properly Kill The Window

begin

 

   
 

اولين کاري که انجام مي دهيم اينست که ببينيم آيا در حالت تمام صفحه هستيم يا خير . اگر بوديم بايد به صفحه desktop برگرديم . ما مي توانيم پنجره را نابود کنيم (destroy) قبل از اينکه حالت تمام صفحه را غير فعال کنيم ولي بر روي بعضي از کارتهاي گرافيکي اين امر منجر به خراب شدن desktop خواهد شد . پس ما اول حالت تمام صفحه را غير فعال مي کنيم . اينکار جلوي خراب شدن desktop را مي گيرد و بر روي کارتهاي nvidia و 3dfx کار خواهد کرد . ( بر روي سيستم من با کارت گرافيک Radeon 9000 Pro IIو ويندوز 2000 سرور با سرويس پک 4 باز هم کار نمي کند !!! )

 
   

 

  if FullScreen then   //Are We In Fullscreen Mode?

    begin

 

   
 

ما از ChangeDisplaySettings(devmode(nil^),0); براي باز گشت به desktop اصلي استفاده مي کنيم . ارسال nil به عنوان پارامتر اول و صفر به عنوان پارامتر دوم به ويندوز مي گويد که از مقادير ثبت شده در رجيستري براي تنظيم desktop استفاده کند ( براي رزولوشن ، فرکانس ، تعداد رنگ و ... ) . سپس ما کرسر (cursor) را مجددا نمايش مي دهيم .

 
   

 

      ChangeDisplaySettings(devmode(nil^),0); //Switch Back To The Desktop

      showcursor(true);  //Show The Mouse Pointer

    end;

 

   
 

کد زير ابتدا چک مي کند که آيا ما از Rendering Context استفاده مي کنيم يا نه . اگر استفاده نمي کنيم به قسمت پايين تر براي چک کردن اينکه آيا از Device Context استفاده مي کنيم يا نه مي رود .

 
   

 

  if h_rc<>0 then       //Is There A Rendering Context?

    Begin

 

   
 

اگر يک Rendering Context داريم کد زير چک مي کند تا ببيند که آيا مي توانيم آنرا از بين ببريم (release) يا نه ( جدا کردن h_rc از h_dc ) . به روشي که من براي چک کردن خطا به کار برده ام توجه کنيد . ابتدا با دستور wglMakeCurrent(h_Dc,0) به برنامه مي گويم که سعي در بستن RC کند . سپس چک مي کنم که آيا اينکار بدرستي انجام شده است يا نه . ترکيب چند خط کد در يک خط .

 
   

 

      if (not wglMakeCurrent(h_Dc,0)) then   //Are We Able To Release Dc and Rc contexts?

 

   
 

اگر ما نتوانيم که RC و DC را از بين ببريم با يک پيغام خطا برنامه اعلام خطا مي کند . براي راهنماي MessageBox لطف کرده و در محيط دلفي روي اين دستور دکمه F1 را بزنيد  

 
   

 

        MessageBox(0,'Release of DC and RC failed.',' Shutdown Error',MB_OK or MB_ICONERROR);

 

   
 

>حالا ما سعي مي کنيم که Rendering Context را از بين ببريم . اگر به خطايي برخورديم پيغامي نمايش داده خواهد شد .

 
   

 

      if (not wglDeleteContext(h_Rc)) then   //Are We Able To Delete The Rc?

        begin

 

   
 

اگر ما نتوانيم Rendering Context را از بين ببريم کد زير پيغام خطايي نمايش خواهد داد و به h_Rcمقدار صفر خواهد داد .

 
   

 

          MessageBox(0,'Release of Rendering Context failed.',' Shutdown Error',MB_OK or MB_ICONERROR);

          h_Rc:=0;                           //Set Rc To Null

        end;

    end;

 

   
 

حالا ما چک مي کنيم که آيا برنامه ما از Device Context استفاده مي کند يا نه و سپس سعي در بستن آن مي کنيم . اگر نتوانيم زير پيغام خطايي نمايش خواهيم داد و به h_Dcمقدار صفر خواهيم داد .

 
   

 

  if (h_Dc=1) and (releaseDC(h_Wnd,h_Dc)<>0) then   //Are We Able To Release The Dc?

    Begin

      MessageBox(0,'Release of Device Context failed.',' Shutdown Error',MB_OK or MB_ICONERROR);

      h_Dc:=0;                           //Set Dc To Null

    end;

 

   
 

حالا همان کارها را در مورد هندل پنجره انجام مي دهيم .

 
   

 

  if (h_Wnd<>0) and (not destroywindow(h_Wnd))then   //Are We Able To Destroy The Window?

    begin

      MessageBox(0,'Could not release hWnd.',' Shutdown Error',MB_OK or MB_ICONERROR);

      h_Wnd:=0;                          //Set hWnd To Null

    end;

 

   
 

<بخش بعدي کد صفحه OpenGL را براي ما مي سازد . من مدتي در اين فکر بودم که من بايد يک صفحه ثابت تمام صفحه را بسازم که مقداري کد اضافه نخواهد و يا اينکه يک صفحه کاربر پسند (user friendly) با مقداري کد نويسي بيشتر . من به اين نتيجه رسيدم که گزينه دوم بهترين انتخاب است . من هميشه با اين سوال در email مواجه بودم که براي اينکه يک صفحه غير از تمام صفحه بخواهم چه بايد بکنم . چگونه caption فرم ( صفحه ) را تغيير بدهم . چگونه رزولوشن يا تعداد رنگها را مشخص کنم . کد زير پاسخي براي تمام اينهاست .
همانطور که مي بينيد اين تابع يک مقدار بولي (Boolean) برمي گرداند . پنج ورودي شامل : نوشته بالاي صفحه ، عرض پنجره ، ارتفاع پنجره ، تعداد بيتها ( 16/24/32) و در نهايت حالت تمام صفحه . ما در نهايت true را بر مي گردانيم اگر همه چيز به خوبي پيش برود .

 
   

 

function CreateGlWindow(title:Pchar; width,height,bits:integer;FullScreenflag:bool):boolean stdcall;

 

   
 

وقتي ما از ويندوز مي خواهيم که فرمت پيکسلي را که ما مي خواهيم مطابقت دهد ، تعداد مودها (mode)يي که ويندوز براي ما پيدا کرده است در متغير PixelFormatذخيره مي شود .

 
   

 

var

  Pixelformat: GLuint;           //Holds The Result After Searching For A Match

 

   
 

Wcبراي نگه داشتن ساختار کلاس پنجره ما استفاده مي شود که اطلاعات مربوط به پنجره ما در آن نگه داري مي شود . با تغيير دادن فيلدهاي مختلف اين کلاس ما مي توانيم شکل و رفتار پنجره را تغيير دهيم . هر پنجره به يک کلاس پنجره تعلق دارد . شما بايد يک کلاس براي پنجره رجيستر کنيد .

 
   

 

  wc:TWndclass;                  //Windows Class Structure

 

   
 

dwExStyleو dwStyleدر حالتهاي پيشرفته و معمولي اطلاعات حالت (style)پنجره ما را نگه مي دارند . من از متغيرها براي ذخيره کردن اين اطلاعات استفاده مي کنم تا بتوانم حالت پنجره را بسته به نياز تغيير دهم . ( براي حالت popupيا تمام صفحه يا داراي حاشيه براي حالت غير تمام صفحه ) .

 
   

 

  dwExStyle:dword;               //Extended Window Style

  dwStyle:dword;                 //Window Style

 

   
 

متغير pfd نوع و حالت نقاط را نگه مي دارد . dmScreenSettings حالت صفحه و h_Instance شماره instance برنامه را

 
   

 

  pfd: pixelformatdescriptor;    //Tells Windows How We Want Things To Be

  dmScreenSettings: Devmode;     //Device Mode

  h_Instance:hinst;              // Holds The Instance Of The Application

 

   
 

دو خط بعدي ابتداinstance برنامه را پيدا کرده و سپس متغير عمومي FullScreen را مساوي fullscreenflag قرار مي دهيم .

 
   

 

begin

  h_instance:=getmodulehandle(nil); //Grab An Instance For Our Window

  FullScreen:=FullScreenflag;       //Set The Global Fullscreen Flag

 

   
 

حالا ما کلاس پنجره خود را تعريف مي کنيم . حالت CS_HREDRAW و CS_VREDRAW پنجره را وادار مي کنند که هر بار که تغيير اندازه داد دوباره رسم شود . CS_OWNDCيک DC اختصاصي براي پنجره مي سازد . يعني اينکهDC بين برنامه ها مشترک نيست و براي هر برنامه يک عدد اختصاصي و يکتا (unique) است . WndProc تابعي است که پيغامها را در برنامه گرفته و پردازش مي کند . ساير اطلاعات اضافه استفاده نمي شود . پس دو متغير را مقدار صفر مي دهيم . سپس مقدار instance را تنظيم مي کنيم . بعد ما مقدار آيکون را صفر قرار مي دهيم زيرا از آيکون براي برنامه مان استفاده نمي کنيم ، و براي ماوس از حالت استاندارد استفاده مي کنيم . رنگ پس زمينه مهم نيست زيرا آنرا توسط OpenGL تعريف کرده ايم . ما از منو استفاده نخواهيم کرد ، پس مقدار آنرا nil قرار مي دهيم . و در نهايت نام کلاس آنرا OpenGL (براي راحتي کار) قرار مي دهيم .

 
   

 

  with wc do

    begin

      style:=CS_HREDRAW or CS_VREDRAW or CS_OWNDC;   //Redraw On Size -- Own DC For Window

      lpfnWndProc:=@WndProc;                         //WndProc Handles The Messages

      cbClsExtra:=0;                                 //No Extra Window Data

      cbWndExtra:=0;                                 //No Extra Window Data

      hInstance:=h_Instance;                         //Set The Instance

      hIcon:=LoadIcon(0,IDI_WINLOGO);                //Load The Default Icon

      hCursor:=LoadCursor(0,IDC_ARROW);              //Load The Arrow Pointer

      hbrBackground:=0;                              //No BackGround Required For OpenGL

      lpszMenuName:=nil;                             //We Don't Want A Menu

      lpszClassName:='OpenGl';                       //Set The CLass Name

    end;

 

   
 

حالا بايد کلاس خود را رجيستر کنيم . اگر خطايي رخ دهد پيغام به نمايش درآمده و از برنامه خارج مي شويم .

 
   

  if  RegisterClass(wc)=0 then                       //Attempt To Register The Window Class

    begin

      MessageBox(0,'Failed To Register The Window Class.','Error',MB_OK or MB_ICONERROR);

      CreateGLwindow:=false;                         //Return False

      exit;                                          //Exit

    end;

 

   
 

حالا ما چک مي کنيم که آيا در حالت تمام صفحه قرار داريم يا خير .

 
   

 

  if FullScreen then                                 //Attempt Fullscreen Mode

    begin

 

   
 

اين قسمت از کد جايي است که اکثر کاربران با آن مشگل دارند . چند چيز خيلي مهم وجود دارد که شما بايد در حالت تمام صفحه به آن توجه کنيد . بايد مطمئن شويد که عرض و ارتفاع حالت تمام صفحه با عرض و ارتفاع صفحه شما يکي است و مهمترين چيز آنست که ابتدا به حابت تمام صفحه سوئيچ کنيد قبل از آنکه پنجره خود را بسازيد . در اين کد شما نبايد نگران اين موضوع باشيد ، اندازه حالت تمام صفحه و پنجره شما يکي است .

 
   

 

      ZeroMemory( @dmScreenSettings, sizeof(dmScreenSettings) );  //Makes Sure Memory's Available

      with dmScreensettings do

        begin

          dmSize := sizeof(dmScreenSettings);         //Size Of The Devmode Structure

          dmPelsWidth  := width;                   //Selected Screen Width

              dmPelsHeight := height;                     //Selected Screen Height

          dmBitsPerPel := bits;                       //Selected Bits Per Pixel

          dmFields     := DM_BITSPERPEL or DM_PELSWIDTH or DM_PELSHEIGHT;

        end;

 

   
 

در کد بالا ما فضاي لازم براي تنظيمات خود را اختصاص مي دهيم . ما عرض ، ارتفاع و تعداد رنگها را به مقداري که براي پنجره خود مي خواهيم تنظيم مي کنيم . در کد زير ما سعي مي کنيم که تنظيمات خود را اعمال کنيم . ما تمام اين اطلاعات را در dmScreenSettings ذخيره مي کنيم . در کد پايين دستور ChangeDisplaySettingsسعي مي کند که صفحه را به حالتي که توسط dmScreenSettings مشخص شده ببرد . من از پارامتر CDS_FULLSCREEN براي تغيير مود استفاده کردهيم ، زيرا اين حالت دکمه start و taskbar را مخفي ميکند بدون اينکه اندازه ساير پنجره هاي باز را تغيير دهد يا مکان آنها را عوض کند وقتي که به حالت تمام صفحه مي رويد و يا به حالت desktop بر مي گرديد .

 
   

 

      //Try To Set The Selected Mode And Get Results. CDS_FullScreen Gets Rid Of The Start Bar

      if (ChangeDisplaySettings(dmScreenSettings, CDS_FullScreen))<>DISP_CHANGE_SUCCESSFUL THEN

        Begin

 

   
 

اگر نتوانيم به حالت درخواست شده سوئيچ کنيم کد زير اجرا مي شود . اگر حالت تمام صفحه مورد نظر وجود نداشته باشد کد زير پيغامي با دو گزينه نمايش مي دهد . يکي براي اجرا در حالت پنجره اي و ديگري براي خروج از برنامه .

 
   

 

          if MessageBox(0,'This FullScreen Mode Is Not Supported. Use Windowed Mode Instead?'

                                             ,'NeHe GL',MB_YESNO or MB_ICONEXCLAMATION)= IDYES then

 

   
 

اگر کاربر تصميم بگيرد که از حالت پنجره اي استفاده کند متغير fullscreen به مقدار نادرست تغيير داده مي شود و اجراي برنامه ادامه مي يابد .

 
   

 

                FullScreen:=false   //Select The Windowed Mode

          else

            begin

 

   
 

اگر کاربر تصميم به خروج بگيرد يک پيغام به کاربر مي گويد که برنامه بسته خواهد شد . مقدار نادرست برگردانده خواهد شد که به برنامه مي گويد پنجره ساخته نشده است و برنامه بسته مي شود .

 
   

 

              //Popup A Message Box Letting The User Know The Program Is Closing

              MessageBox(0,'Program Will Now Close.','Error',MB_OK or MB_ICONERROR);

              CreateGLWindow:=false;    //Return False

            end;

          end;

    end;

 

   
 

چون حالت تمام صفحه ممکن است به خظا برخورده باشد و کاربر تصميم به اجراي برنامه در حالت پنجره اي گرفته باشد ، ما بايد دوباره متغير fullscreen را چک کنيم .

 
   

 

  if FullScreen then  //Check If We're Still In Fullscreen Mode

    begin

 

   
 

اگر ما حالت تمام صفحه را داشته باشيم ما بايد حالت پيشرفته WS_EX_APPWINDOW را انتخاب کنيم که ساير پنجره هاي سطح بالا را به taskbar ببرد وقتي که پنجره ما قابل رويت (visible) مي شود . در حالت پنجره اي ما حالت WS_POPUP را انتخاب مي کنيم که يک پنجره بدون حاشيه (border) مي سازد که براي حالت تمام صفحه هم مناسب است . در نهايت ما نشانگر ماوس را هم غير فعال مي کنيم . اگر برنامه از ماوس استفاده نمي کند اين کار ايده خوبي است . به هر حال تصميم با شماست .

 
   

 

      dwExStyle:=WS_EX_APPWINDOW;  //Extended Window Style

      dwStyle:=WS_popup or WS_CLIPSIBLINGS or WS_CLIPCHILDREN; //Window Style

      Showcursor(false);           //Hide Mouse Pointer

    end

  else

    begin

 

   
 

اگر ما از حالت پنجره اي به جاي تمام صفحه استفاده مي کنيم ، بايد حالت WS_EX_WINDOWEDGE را به حالت پيشرفته اضافه مي کنيم . اين کار حالت سه بعدي بهتري به پنجره مي دهد . براي style ما از WS_OVERLAPPEDWINDOW به جاي WS_POPUP استفاده مي کنيم . WS_OVERLAPPEDWINDOW يک پنجره با title bar ، قاب قابل تغيير اندازه ، منوي اصلي و دکمه minimize/maximize مي سازد .

 
   

 

      dwExStyle:=WS_EX_APPWINDOW or WS_EX_WINDOWEDGE;   //Extended Window Style

      dwStyle:=WS_OVERLAPPEDWINDOW or WS_CLIPSIBLINGS or WS_CLIPCHILDREN; //Windows Style

    end;

 

   
 

در بخش بعدي ما براي ساختن پنجره خود اقدام مي کنيم و چک مي کنيم که آيا درست مطابق خواسته ما ساخته شده است يا نه . ما تمام مقاديري را که CreateWindowEx() نياز دارد را برايش مي فرستيم . حالت پيشرفته اي را که تصميم به استفاده از آن گرفته ايم . نام کلاس ( همان نامي که در موقع رجيستر کردن مشخص کرديم ) . نوشته بالاي صفحه ، حالت پنجره ، مختصات بالا – سمت چپ پنجره ( 0و0 بهترين حالت است ) ، عرض و ارتفاع پنجره ، ما يک پنجره والد (parent) نمي خواهيم و همينطور منو پس اين دو پارامتر را تهي (nil) مي فرستيم . ما instance پنجره را و در نهايت هم يک تهي ديگر به عنوان پارامتر مي فرستيم .
توجه کنيد که ما WS_CLIPSIBLINGS و WS_CLIPSIBLINGS را به حالت پنجره مان اضافه کرده ايم . WS_CLIPSIBLINGSو WS_CLIPCHILDRENهر دو براي درست کار کردن OpenGL لازم هستند . اين حالتها از رسم برروي صفحه ما و همينطور از رسم درون صفحه ما توسط ساير برنامه ها جلوگيري مي کنند .

 
   

 

  H_wnd:=CreateWindowEx(dwExStyle,                   //Extende Style For The Window

                               'OpenGl',             //Class Name

                               Title,                //Window Title

                               dwStyle,              //Window Style

                               0,0,                  //Window Position

                               width,height,         //Selected Width and Height

                               0,                    //No Parent Window

                               0,                    //No Menu

                               hinstance,            //Instance

                               nil);                 //Don't Pass Anything To WM_CREATE

 

   
 

حالا ما تست مي کنيم تا ببينيم آيا پنجره ما بدرستي ساخته شده است يا خير . اگر پنجره ما ساخته شده باشد h_Wnd شامل اشاره گري (handle)به صفحه ما خواهد بود . اگر پنجره بدرستي ساخته نشود کد زير يک پيغام خطا نمايش مي دهد و از برنامه خارج مي شود .

 
   

 

  if h_Wnd=0 then              //If The Window Creation Failed

    begin

      KillGlWindow();          //Reset The Display

      MessageBox(0,'Window creation error.','Error',MB_OK or MB_ICONEXCLAMATION);

      CreateGLWindow:=false;   //Return False

      exit;

    end;

 

   
 

کد زير يک فرمت براي نقاط (pixel format) تعريف مي کند . ما فرمتي را انتخاب مي کنيم که از OpenGL و همينطور از بافر دوگانه را پشتيباني کند ، و RGBA را (Red,Green,Blue,Alpha channel) . ما فرمتي را انتخاب مي کنيم که تعداد رنگهاي آن با مقداري که قبلاً تصميم گرفته بوديم يکي باشد (16bit,24bit,32bit) . در نهايت ما يک Z-Buffer 16 بيتي تعريف مي کنيم . ساير مقادير يا استفاده نمي شوند و يا مهم نيستند .

 
   

 

  with pfd do    //Tells Windows How We Want Things To Be

    begin

      nSize:= SizeOf( PIXELFORMATDESCRIPTOR ); // Size Of This Pixel Format Descriptor

      nVersion:= 1;                            // Version Number (?)

      dwFlags:= PFD_DRAW_TO_WINDOW             // Format Must Support Window

        or PFD_SUPPORT_OPENGL                  // Format Must Support OpenGL

        or PFD_DOUBLEBUFFER;                   // Must Support Double Buffering

      iPixelType:= PFD_TYPE_RGBA;              // Request An RGBA Format

      cColorBits:= bits;                       // Select Our Color Depth

      cRedBits:= 0;                            // Color Bits Ignored

      cRedShift:= 0;

      cGreenBits:= 0;

      cBlueBits:= 0;

      cBlueShift:= 0;

      cAlphaBits:= 0;                          // No Alpha Buffer

      cAlphaShift:= 0;                         // Shift Bit Ignored

      cAccumBits:= 0;                          // No Accumulation Buffer

      cAccumRedBits:= 0;                       // Accumulation Bits Ignored

      cAccumGreenBits:= 0;

      cAccumBlueBits:= 0;

      cAccumAlphaBits:= 0;

      cDepthBits:= 16;                         // 16Bit Z-Buffer (Depth Buffer)

      cStencilBits:= 0;                        // No Stencil Buffer

      cAuxBuffers:= 0;                         // No Auxiliary Buffer

      iLayerType:= PFD_MAIN_PLANE;             // Main Drawing Layer

      bReserved:= 0;                           // Reserved

      dwLayerMask:= 0;                         // Layer Masks Ignored

      dwVisibleMask:= 0;

      dwDamageMask:= 0;

    end;

 

   
 

اگر در زمان ساختن صفحه خطايي رخ ندهد ما سعي در گرفتن يک Device Context براي OpenGL مي کنيم . اگر ما نتوانيم يک DC بگيريم خطايي نمايش داده شده و از برنامه خارج مي شويم .

 
   

 

  h_Dc := GetDC(h_Wnd);                        // Try Getting A Device Context

  if h_Dc=0 then                               // Did We Get Device Context For The Window?

    begin

      KillGLWindow();                          //Reset The Display

      MessageBox(0,'Cant''t create a GL device context.','Error',MB_OK or MB_ICONEXCLAMATION);

      CreateGLWindow:=false;                   //Return False

      exit;

    end;

 

   
 

اگر توانستيم يک DC براي OpenGL در نظر بگيريم حالا بايد به دنبال يک pixel format که با مال ما يکي باشد بگرديم . اگر ويندوز نتواند چنين حالتي را پيدا کند پيغام خطايي نمايش داده شده و از برنامه خارج مي شويم .

 
   

 

  PixelFormat := ChoosePixelFormat(h_Dc, @pfd);// Finds The Closest Match To The Pixel Format We Set Above

  if (PixelFormat=0) then                      //Did We Find A Matching Pixelformat?

    begin

      KillGLWindow();                          //Reset The Display

      MessageBox(0,'Cant''t Find A Suitable PixelFormat.','Error',MB_OK or MB_ICONEXCLAMATION);

      CreateGLWindow:=false;                   //Return False

      exit;

    end;

 

   
 

اگر ويندوز توانست حالت نقاط مورد نظر را پيدا کند ما سعي مي کنيم که آنرا به کار بگيريم . اگر نتوانيم پيغام خطايي نمايش داده شده و از برنامه خارج مي شويم .

 
   

 

  if (not SetPixelFormat(h_Dc,PixelFormat,@pfd)) then  //Are We Able To Set The Pixelformat?

    begin

      KillGLWindow();                          //Reset The Display

      MessageBox(0,'Cant''t set PixelFormat.','Error',MB_OK or MB_ICONEXCLAMATION);

      CreateGLWindow:=false;                   //Return False

      exit;

    end;

 

   
 

اگر حالت نقاط به کار گرفته شد ما سعي در بدست آوردن يک Rendering Context مي کنيم . اگر نتوانيم پيغام خطايي نمايش داده شده و از برنامه خارج مي شويم .

 
   

 

  h_Rc := wglCreateContext(h_Dc);              //Are We Able To Get A Rendering Context?

  if (h_Rc=0) then

    begin

      KillGLWindow();                          //Reset The Display

      MessageBox(0,'Cant''t create a GL rendering context.','Error',MB_OK or MB_ICONEXCLAMATION);

      CreateGLWindow:=false;                   //Return False

      exit;

    end;

 

   
 

اگر به هيچ خطايي برنخورده باشيم و توانسته باشيم که DC و RC مورد نظر را بسازيم تنها چيزي که بافي مي ماند فعال ساختن RC است . اگر نتوانيم آنرا فعال بسازيم پيغام خطايي نمايش داده شده و از برنامه خارج مي شويم .

 
   

 

  if (not wglMakeCurrent(h_Dc, h_Rc)) then     //Are We Able To Activate The Rendering Context?

    begin

      KillGLWindow();                          //Reset The Display

      MessageBox(0,'Cant''t activate the GL rendering context.','Error',MB_OK or MB_ICONEXCLAMATION);

      CreateGLWindow:=false;                   //Return False

      exit;

    end;

 

   
 

اگر همه چيز بخوبي پيش رفته باشد و پنجره OpenGL ما ساخته شده باشد ما پنجره خود را به نمايش در مي آوريم ، آنرا به صورت جلو زمينه (foreground)در مي آوريم ( تا از priority بالاتري استفاده کند ) و سپس کنترل را به صفحه خود منتقل مي کنيم . سپس با صدا زدن ReSizeGLSceneبا پارامترهاي عرض و ارتفاع صفحه حالت پرسپکتيو OpenGL را تنظيم مي کنيم .

 
   

 

  ShowWindow(h_Wnd,SW_SHOW);       //Show The Window

  SetForegroundWindow(h_Wnd);      //Slightly Higher Priority

  SetFOcus(h_Wnd);                 //Set Keyboard Focus To The Window

  ReSizeGLScene(width,height);     //Set Up Our Perspective Gl Screen

 

   
 

در نهايت روال InitGL() صدا زده مي شود تا نورها texture و هر آن چه لازم داريم تنطيم شود . شما مي توانيد خطاهاي مختلف را در InitGL چک کنيد و درست را بفرستيد اگر همه چيز بخوبي پيش رفت و گرنه نادرست را برگردانيد تا بتوانيد برنامه را متوقف کنيد . اگر شما نادرست را برگردانيد خطوط زير پيغام خطايي برگردانده و از برنامه خارج مي شويم .

 
   

 

  if (not InitGl()) then           //Can we Initialize The Newley Created GL Window

    begin

      KillGLWindow();              //Reset The Display

      MessageBox(0,'initialization failed.','Error',MB_OK or MB_ICONEXCLAMATION);

      CreateGLWindow:=false;       //Return False

      exit;

    end;

 

   
 

حالا که همه چيز بخوبي پيش رفته و به خطايي برنخورده ايم مقدار درست را بر مي گردانيم تا به WinMain() هم اين موضوع را اعلام کنيم که از برنامه خارج نشود .

 
   

 

  CreateGLWindow:=true;            //Succes

end;

 

   
 

اينجا جايي است که ما تمام پيغامهايي را که به پنجره ما مي رسد پردازش مي کينم . وقتي ما کلاس پنجره خود را رجيستر کرديم ما مشخص کرديم که براي پيغامها به اين بخش از برنامه ما مراجعه شود .

 
   

 

function WndProc(hWnd: HWND;         //Handle For The Window

                 message: UINT;      //Message For This Window

                 wParam: WPARAM;     //Additional Message Information

                 lParam: LPARAM):    //Additional Message Information

                                  LRESULT; stdcall;

 

begin

 

   
 

ابتدا حالتي را که محافظ صفحه نمايش (sceern saver) مي خواهد شروع شود و يا مانيتور مي خواهد به حالت خاموش برود (power save) چک کرده و جلوي اين حالات را مي گيريم .

 
   

 

  if message=WM_SYSCOMMAND then    //Intercept System Commands

    begin

      case wParam of                         //Check System Calls

        SC_SCREENSAVE,SC_MONITORPOWER:       //Screensaver Trying To Start, Monitor Trying To Enter Powersave?

          begin

            result:=0;                       //Prevent This From Happening

            exit;                            //Exit

          end;

      end;

    end;

 

   
 

حالا بر اساس نوع پيغامها تصميم مي گيريم .

 
   

 

  case message of       // Tells Windows We Want To Check The Message

 

   
 

ما حالت WM_ACTIVATE را چک مي کنيم تا ببينيم آيا پنجره ما همچنان فعال است يا نه . اگر پنجره ما کوچک شده بود (minimize)مقدار متغير active را "نادرست" کرده و در غير اينصورت "درست" مقدار دهي مي کنيم .

 
   

 

    WM_ACTIVATE:

      begin

        if (Hiword(wParam)=0) then  //Check Minimization State

          active:=true              //Program Is Active

        else

          active:=false;            //Program Is No Longer Active

        Result:=0;                  //Return To The Message Loop

      end;

 

   
 

در حالت WM_CLOSEپنجره ما بسته شده است . ما يک پيغام خروج مي فرستيم تا از حلقه اصلي خارج شويم . متغير done به "درست" مقدار دهي مي شود تا از حلقه اصلي در WinMain() خارج شويم و برنامه بسته شود .

 
   

 

    WM_CLOSE:                       //Did We Get A Close Message

      Begin

        PostQuitMessage(0);         //Send A Quit Message

        result:=0                   //Return To The Message Loop

      end;

 

   
 

اگر کليدي در حالت فشرده شده باشد ما مي توانيم آنرا با چک کردن wParam بدست آْوريم . سپس ما آنرا در آرايه Keys به حالت "درست" در مي آوريم . در اين روش ما بعداً مي توانيم اين آرايه را چک کنيم و دکمه هاي فشرده شده را بدست آوريم . اين روش همچنين به ما اين امکان را مي دهد که فشرده شدن همزمان چند کليد را بفهميم .

 
   

 

    WM_KEYDOWN:                     //Is A Key Being Held Down?

      begin

        keys[wParam] := TRUE;       //If So, Mark It As True

        result:=0;                  //Return To The Message Loop

      end;

 

   
 

اگر کليدي رها شود ما آنرا با چک کردن wParam بدست مي آوريم . سپس وضعيت آنرا در آرايه Keys به نادرست تغيير مي دهيم . در اين روش ما مي توانيم بفهميم که آيا دکمه همچنان فشرده شده يا رها شده است . هر کليد بر روي صفحه کليد عددي بين صفر تا 255 بر مي گرداند . به عنوان مثال وقتي دکمه اي با کد 40 فشار داده مي شود ما keys[40] را "درست" مقدار دهي مي کنيم و وقتي رها مي شود دوباره به "نادرست" برمي گردانيم . اين روشي است که من براي ذخيره کليدها بکار مي برم .

 
   

 

    WM_KEYUP:                       //Is A Key Being Released?

      begin

            keys[wParam] := FALSE;      //If So, Mark It As False

        result:=0;                  //Return To The Message Loop

      end;

 

   
 

وقتي پنجره اندازه اش تغيير مي کند message با مقدار WM_SIZE پر مي شود . ما مقادير LOWORD و HIWORDاز lParam را براي عرض و ارتفاع جديد مي خوانيم و صفحه OpenGL را با مقادير جديد مقدار دهي مي کنيم .

 
   

 

    WM_SIZe:                        //Resize The GL Window

      begin

            ReSizeGLScene(LOWORD(lParam),HIWORD(lParam)); //Loword=Width, Highword=Height

        result:=0;                  //Return To The Message Loop

      end

    else

 

   
 

ساير پيغامها را نيز به DefWindowProc مي فرستيم تا ويندوز کارهاي مربوط به آنها را انجام دهد .

 
   

 

      //Pass All Unhandled Messages To DefWinProc

      begin

            Result := DefWindowProc(hWnd, message, wParam, lParam);

      end;

    end;

end;

 

   
 

اين بخش مدخل برنامه ما است . اين جايي است که ما روتين ساختن پنجره را صدا مي زنيم و به عملکرد کاربر واکنش نشان مي دهيم .

 
   

 

function WinMain(hInstance: HINST;          //Instance

                         hPrevInstance: HINST;      //Previous Instance

                         lpCmdLine: PChar;          //Command Line Parameters

                         nCmdShow: integer):        //Window Show State

                                    integer; stdcall;

 

   
 

ما دو متغير تعريف مي کنيم . msg براي اين استفاده مي شود که ببينيم آيا پيغامي براي واکنش نشان دادن وجود دارد يا نه . متغير done را هم به "نادرست" تنظيم مي کنيم . اين بدان مهناست که تا زماني که همين مقدار را دارد برنامه ما به کار خود ادامه مي دهد . و وقتي که "درست" شد ، از برنامه خارح مي شويم .

 
   

 

var

  msg: TMsg;      // Windows Message Structure

  done: Bool;     // Variable To Exit The Loop

 

begin

  done:=false;

 

   
 

اين بخش از کد اختياري است . از کاربر مي پرسد که آيا مايل است برنامه در حالت تمام صفحه اجرا شود يا خير و اگر نه متغير fullscreen را به حالت "نادرست" مي برد تا برنامه در حالت پنجره اي به جاي تمام صفحه اجرا شود .

 
   

 

  //Ask The User Which Screenmode They Prefer

  if MessageBox(0,'Would You Like To Run In FullScreen Mode?','Start FullScreen',

                             MB_YESNO or MB_ICONQUESTION)=IDNO then

    FullScreen:=false      //Windowed Mode

  else

    FullScreen:=true;      //Fullscreen Mode

 

   
 

اينجا جايي است که ما دستور ساختن پنجره OpenGL خومان را مي دهيم . ما مقادير نوشته ي بالاي صفحه ، عرض ، ارتفاع ، عمق رنگ و مقدار تمام صفحه بودن يا نبودن را مي فرستيم . دقت کنيد که اين بخش از کد تا چه حدي زيبا و کارآمد است . اگر پنجره بدرستي ساخته نشود مقدار "نادرست" برگردانده شده و ما از برنامه خارح مي شويم .

 
   

 

  if not CreateGLWindow('NeHe''s OpenGL Framework',640,480,16,FullScreen) then //Could We Create The OpenGl Window?

    begin

      Result := 0;    //Quit If The Window Wasn't Created

      exit;

    end;

 

   
 

اين جايي است که حلقه ما شروع مي شود . تا وقتي متغير done "نادرست" است حلقه اجرا مي شود و در غير اينصورت از حلقه خارج مي شويم .

 
   

 

  while not done do   //Loop That Keeps The Program Running

    begin

 

   
 

اولين چيزي که بايد چک کنيم اين است که آيا پيغامي جهت پردازش وجود دارد يا خير . با استفاده از PeekMessage به جاي GetMessageيک حالت پيشرفته تري به برنامه مان مي دهيم . اولي اين مزيت را دارد که اگر پيغامي در کار نباشد به کار ادامه مي دهد ولي GetMessage تا زماني که پيغامي نرسد اجراي برنامه ما را متوقف مي کند . ( اين پيغام لزوماً پيغامهايي که در بالا ديديد نيست . بلکه مي تواند پيغام رسم (paint) و يا هر پيغام ديگري نيز باشد )

 
   

 

      if (PeekMessage(msg, 0, 0, 0, PM_REMOVE)) then  //Is There A Message Running

        begin

 

   
 

در اين بخش ما چک مي کنيم که آيا پيغامي براي بستن برنامه دريافت کرده ايم يا خير . اگر آري متغير done را "درست" مقدار دهي کرده تا از حلقه و سپس از برنامه خارج شويم .

 
   

 

          if msg.message=WM_QUIT then                 //Have We Received A Quit Message?

            done:=true                                //If So, Done=True

          else

            begin

 

   
 

اگر نه ما پيغام را ترجمه کرده و سپس آنرا ارسال مي کنيم تا WndProc و يا ويندوز آنرا دريافت کنند .

 
   

 

                  TranslateMessage(msg);                  //Translate The Message

                  DispatchMessage(msg);                   //Dispatch The Message

                end;

        end

      else

        begin

 

   
 

اگر پيغامي در کار نبود ما منظره مورد نطر را در OpenGL رسم مي کنيم . اولين خط چک مي کند که آيا برنامه فعال است يا نه ؟ اگر ESC زده شده باشد ما بايد از برنامه خارج شويم و احتياجي به رسم اشياء نيست .

 
   

 

          //Draw The GL Scene. Watch For ESC Key Aned Quit Messages from DrawGLScene()

          if (active and not(DrawGLScene()) or keys[VK_ESCAPE]) then

            done:=true                                                                         //ESC PRessed Or DrawGLScene Signalle A Quit

          else

 

   
 

اگر برنامه فعال بود و ESC هم زده نشده بود و همينطور توانسته بوديم اشياء را رسم کنيم بافرها را تعويض مي کنيم . ( با استفاده از دو بافر ما از پرش تصوير جلوگيري مي کنيم ) با استفاده از دو بافر ما مي توانيم عمليات ترسيم اشياء را در صفحه دوم ( و مخفي از نظر کاربر ) انجام دهيم و سپس وقتي جاي دو بافر را عوض مي کنيم تصوير به يکباره ظاهر مي شود و حالت رسم از ديد کاربر مخفي مي ماند .

 
   

 

            SwapBuffers(h_Dc);              //Not Time TO Quit Yet, Update The Screen

        end;

    end;

 

   
 

اگر متغير done "نادرست" نباشد بايد از برنامه خارج شويم . يعني بايد پنجره OpenGL را ببنديم و دستور خروج را به برنامه بدهيم .

 
   

 

  killGLwindow();                           //Shutdown

  result:=msg.wParam;

end;

 

   
 

اين بخش هم که روتين اصلي برنامه ما است .

 
   

 

begin

  active:=true;                             //The Active Variable Is Set To True By Default

  WinMain( hInstance, hPrevInst, CmdLine, CmdShow );   //This Starts the program

end.

 

   
 

من براي ترجمه و اضافه کردن بخشها(ي معدود) حدود 2 تا 3 روز کاري وقت گذاشتم .همينطور درست کردن صفحات سايت و تنظيم آنها حدود 2 روز طول کشيد .اگر جايي ايرادي مي بينيد و يا فکر مي کنيد با اضافه و يا کم کردن بخشهايي به خوانايي و يا افزايش عملکرد برنامه و يا سطح آموزش اضافه مي شود حتماً با من در ميان بگذاريد

 

    
  

دريافت ليست دلفي نوشته شده توسط Peter De Jaegher

 

درس دوم ->