بتـــــاريخ : 2/28/2011 2:00:56 AM
الفــــــــئة
  • الحـــــــــــاسب
  • التعليقات المشاهدات التقييمات
    0 4166 0


    دروس حول مكتبة glut .. دروس على الطاير .. للي يفهم على الطاير

    الناقل : elmasry | العمر :42 | الكاتب الأصلى : الشمري | المصدر : www.arabteam2000-forum.com

    كلمات مفتاحية  :
    دروس مكتبة glut

    السلام عليكم :

    هذه دروس مبسطة حول المكتبة GLUT المساندة لOPENGL

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

    هذه الدروس مقتبسة من عدد من الدروس المتناثرة .. اقول مقتبسة وليس مترجمة ..
    مثلا
    http://www.lighthous...om/opengl/glut/


    ماذا عن دوال Win Api ?
    مميزة ومفيدة ..
    لكن قد تكون اصعب ( او اقول ) طويلة نوعا ما ..
    في دروس NEHE المستخدم هو دوال WIN API ..
    طبعا WIN API تعطيك كل شيء ..
    لكن GLUT تسهل حياتك البرمجية .. باكوادها المختصرة .

    ايهما اتعلم .. GLUT .. او ..WIN API ?
    النتيجة واحدة ... الغرض من تلك المكتبات بالنسبة لنا .. ربط OPENGL بالنافذة ..والتعامل مع الكيبورد والماوس .. وهذا ماتفعله المكتبتان ..
    لكن ..انصحط بتعلم GLUT و WIN API لانك ستواجه دروس واكواد بعضها مكتوب بتلك المكتبة وبعضها بالمكتبة الاخرى .. والامر سهل .,

    اين اجد هذه المكتبة "GLUT" ؟
    حمل من هنا
    http://www.xmission....t-3.7.6-bin.zip

    انسخ GLUT32.DLL في ملف السيستم اللي عندك وهو في الغالب system32 او system ..
    انسخ glut32.lib في ملف المكتبات الخاص بالمصرف اللي عندك


    انسخ ملف الهيدر glut.h والصقه اما في مجلد ملفات الهيدر الرئيسي اللي عندك
    او في داخل احد المجلدات واللذي يسمى GL الموجود في مجلد الملفات الرأسية

    اذا اتبعت الحالة الاولى تستدعيه هكذا

    #include"glut.h"




    او تستدعيه هكذا في الحالة الثانية
    #include"GL/glut.h"

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




    الدرس الاول : ربط النافذة بـOPENGL
    اولا نريد ان نقسم عملنا الى عدة دوال ذلك للتسهيل .. اعيد واكرر للتسهيل فقط .. وانت حر .

    مثلا
    سنقوم بعمل ثلاث دوال
    الاولى نضع فيها اعدادات OPENGL من اعداد لون الخلفية .. الاكساء.. الاضاءة.. الخ
    وسنسميها مثلا
    setting

    الدالة الثانية نسميها reshape .. وستعرف فائدتها .,

    الثالثة . render .. والتي سنضع فيها الرسم ..

    اضافة للدالة الرئيسية main ..

    لاحظ اننا نعمل على الكونسول .... انتبه .



    قم بربط المكتبة glut32.lib و opengl32.lib و glu32.lib
    الصق هذا الكود


    #include<glut.h>
    #include<gl/glu.h>
    #include<gl/gl.h>


    void reshape(int w, int h) {

            glViewport(0, 0, w, h);
            glMatrixMode(GL_PROJECTION);
            glLoadIdentity();
      gluPerspective(45.0, (float)w/(float)h, 1.0, 300.0);
            glMatrixMode(GL_MODELVIEW);
            glLoadIdentity();



    }


    void render(void)
    {
            glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
     
      glFlush();
           
    }

    void main(int argc, char **argv) {
            glutInit(&argc, argv);
            glutInitDisplayMode(GLUT_DEPTH | GLUT_SINGLE | GLUT_RGBA);
            glutInitWindowPosition(100,100);
            glutInitWindowSize(320,320);
            glutCreateWindow("arab team - glut  ");
      glutDisplayFunc(render);
            glutReshapeFunc(reshape);
            glutMainLoop();
    }
    هذا الدرس اطول درس الله يعيننا ..

    glutInit(&argc, argv);
    الدالة السابقة تعد المكتبة وبارمتراتها هي بارمترات main ...

            glutInitDisplayMode(GLUT_DEPTH | GLUT_SINGLE | GLUT_RGBA);
    هنا نعد opengl .. ولها عدة بارمترات
    GLUT_RGB
    GLUT_RGBA
    GLUT_INDEX
    GLUT_SINGLE
    GLUT_DOUBLE
    GLUT_ACCUM
    GLUT_ALPHA
    GLUT_DEPTH
    GLUT_STENCIL
    GLUT_MULTISAMPLE
    GLUT_STEREO
    GLUT_LUMINANCE

    من الصعب شرحها كلها لان هذا يتطلب فهم لعمل opengl .. وهذا خارج عن ما نريده الان ..
    المهم GLUT_RGB او GLUT_RGBA نظام الالوان الذي تريده
    GLUT_SINGLE يعني تريد ان تكتب على سطح واحد فقط .. وبالتالي الحركة لن تكون ناعمة ..
    GLUT_DOUBLE تكتب على سطحين .. وهذا مايزيد نعومة الحركة ..

    GLUT_DEPTH هذا خاص بالعمق .. يعني هل تريد استخدام المحور z يعني الثري دي .. اذا اردت استخدام الثري دي فمرر هذا البارمتر ..

    نحن استخدمنا GLUT_DEPTH | GLUT_SINGLE | GLUT_RGBA
    لاحظ GLUT_SINGLE .. هو ليس الخيار المحبب .. لكن لان GLUT_DOUBLE له اعدادات اخرى فسنؤجله للدروس اللاحقة


            glutInitWindowPosition(100,100);

    هنا نعين احداثيات ناذتنا بالنسبة للشاشة ..

            glutInitWindowSize(320,320);
    الطول والعرض للنافذة

            glutCreateWindow("arab team - glut  ");
    صنعنا النافذة الان .. ونمرر اسم النافذة .. الذي نريد ..

      glutDisplayFunc(render);

    *** مهم ***
    هذه الدالة هي دالة العرض .. يعني اللي رح تعرض الرسوم .. يعني التي يتمر بحلقة دوران loop .. حتى تحفظ الرسم المرسوم وتقوم بتحديثه ..
    المطلوب تمرر لها الدالة التي سترسم بها وهي الان render .. لاحظ ان الدالة render ليس لها بارمترات
    لننتقل الى الدالة render ونرى ما بها ..

            glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    مسحنا البتات (جمع بت) الخاصة بالبفر اللي اخترناه .. مثلا نحن اخترنا GLUT_DEPTH اذا نقوم بتنظيفه
    GL_DEPTH_BUFFER_BIT وهكذا ...
    هذه الدالة من دوال opengl لذا لن نقوم بشرحها لان هذا خارج عن نطاق الدروس ..

      glFlush();
    مهم جدا ..
    هذه الدالة تقوم بدفع الرسم ليظهر الى الشاشة (بأبسط تعبير) .
    يعني اذا رسمت مثلث فلن يظهر الى اذا جاء بعده glFlush ...
    لكن احيانا نستغني عن هذه الدالة وستعرف متى .. باذن الله .

    نعود الى الدالة main وتحديدا الى
            glutReshapeFunc(reshape);
    هذه الدالة مهمة جدا( ومشكلة عند الكثيرين )
    تحدث هذه الدالة اذا تغير حجم النافذة ..
    وبالتالي تقوم بتظبيط الرؤية ... حسب طول وعرض النافذة ..
    تطلب منك دالة .. لها بارمترات الاول للعرض والاخر للطول ..
    نحن سميناها reshape وهي كذا

    void reshape(int w, int h)
     {

            glViewport(0, 0, w, h);
            glMatrixMode(GL_PROJECTION);
            glLoadIdentity();
      gluPerspective(45.0, (float)w/(float)h, 1.0, 300.0);
            glMatrixMode(GL_MODELVIEW);
            glLoadIdentity();



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


    واخيرا
            glutMainLoop();

    التي تدخل برنامجنا (او لعبتنا ) في حلقة من الدوران loop حتى يتم تحديث الرسوم والاشكال المعروضة .. وحتى تأتي رسالة امر بالخروج ..


    هذا الدرس طويل وممل وتأسيسي ...
    الدروس القادمة ممتعة اكثر .
    واسهل .




    الدرس الثاني : استخدام double buffer
    اذا كنت لاتعرف ما معنى double buffer
    سأحاول توضيحه .
    اذا رسمنا بالطريقة العادية .. ستلاحظ ان الشكل المرسوم ""يرمش ""اذا تم تحريكه ..
    للتغلب على هذه المشكلة تم استحداث مايمسى بالسطحين ...double buffer
    لاحظ الصورة

    Posted Image



    هذه صورة تقريبية ..فقط ..

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


    الان سنستخدم double buffer لانه يعطي نعومة للرسم
    غير الدالة
            glutInitDisplayMode(GLUT_DEPTH | GLUT_SINGLE | GLUT_RGBA);
    الى

            glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);
    الان نرسم على السطح الاول ثم نظهره على السطح الظاهر للمستخدم

    لكن يجب عند استخدام double buffer ان تستخدم الدالة
            glutSwapBuffers();
    بدلا من glflush ..
    والسبب ان الدالة glutSwapBuffers تقوم بقلب البفر الخلفي للامام (بأبسط تعبير )
    وبالتالي يظهر الرسم المستخدم .

    ** تنبيه : لاحاجة لاستخدام glFlush اذا كنت تستخدم glutSwapBuffers لان الدالة glutSwapBuffers تقوم بـ glflush ايضا ..



    الدرس الثالث / رسم بعض الاشكال الجاهزة ..
    توفر المكتبة glut عدد من الاشكال الجاهزة .. وهي

    void glutSolidSphere(GLdouble radius,GLint slices, GLint stacks);
    ترسم كرة مصمتة ...
    والبارمترات واضحة فقط قم بتغيير القيم وستفهم ..
    اغلب البارمتر ات هي لتنعيم الرسم ..او لتكبير حجمها .. الخ

    void glutWireSphere(GLdouble radius,
    GLint slices, GLint stacks);
    نفس الدالة السابقة الا انها ترسم خطوط ( شبكة)

    void glutSolidCube(GLdouble size);
    لرسم مكعب

    void glutWireCube(GLdouble size);
    نفس الدالة السابقة الا انها ترسم خطوط ( شبكة)

    void glutSolidCone(GLdouble base, GLdouble height,
    GLint slices, GLint stacks);

    void glutWireCone(GLdouble base, GLdouble height,
    GLint slices, GLint stacks);

    void glutSolidTorus(GLdouble innerRadius,
    GLdouble outerRadius,
    GLint nsides, GLint rings);


    void glutWireTorus(GLdouble innerRadius,
    GLdouble outerRadius,
    GLint nsides, GLint rings);


    void glutSolidDodecahedron(void);

    void glutWireDodecahedron(void);

    void glutSolidOctahedron(void);


    void glutWireOctahedron(void);

    void glutSolidTetrahedron(void);

    void glutSolidIcosahedron(void);

    void glutWireIcosahedron(void);

    void glutWireTetrahedron(void);

    void glutSolidTeapot(GLdouble size);

    void glutWireTeapot(GLdouble size);

    مثلا لرسم ابريق شاهي الربيع :rolleyes:

    void renderScene(void) {
            glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

            glTranslatef(0,0,-5);

            glutSolidTeapot(1);

            glutSwapBuffers();
    }
    طبعا اذا وضعت الوان واضاءة الخ .. سيظهر الشكل ثري دي خالص ,, :)
    لاحظ الدالة
    glTranslatef(0,0,-5);
    هذه تحدد موقع الجسم (وهي من دوال opengl لذا لن اشرحها ..)
    استخدتها حتى يظهر الشكل المرسوم ..
    جرب تغير -5 بارقام اخرى .. ونحو ذلك .

    الملف في المرفقات .


    الدرس الثالث .
    التعامل مع الكيبورد /

    يوجد عدد من الدوال وهي
    void glutSpecialFunc(void (*func)(int key, int x, int y));
    تمرر لها دالة تحتوي على ثلاث بارمترات
    هذه الدالة ..مخصصة لازرار معينة .
    البارمتر الاول سيحمل احد الازرار التالية

    GLUT_KEY_F1
    GLUT_KEY_F2
    GLUT_KEY_F3
    GLUT_KEY_F4
    GLUT_KEY_F5
    GLUT_KEY_F6
    GLUT_KEY_F7
    GLUT_KEY_F8
    GLUT_KEY_F9
    GLUT_KEY_F10
    GLUT_KEY_F11
    GLUT_KEY_F12

    GLUT_KEY_LEFT
    GLUT_KEY_UP
    GLUT_KEY_RIGHT
    GLUT_KEY_DOWN
    GLUT_KEY_PAGE_UP
    GLUT_KEY_PAGE_DOWN
    GLUT_KEY_HOME
    GLUT_KEY_END
    GLUT_KEY_INSERT

    اما البارمتر الثاني فيخبر برنامجنا بموقع الماوس السيني .. والاخير بموقع الماوس الصادي.. لحظة ضغط الزر .

    --------------
    الدالة
    glutKeyboardFunc(void (GLUTCALLBACK *func)(unsigned char key, int x, int y));

    هذه الدالة تطلب دالة تحتوي على ثلاث بارمترات الاول رقم الزر المضغوط ..
    مثلا زر الهروب Esc رقم 27
    زر انتر رقمه 13 وهكذا (( راجع جدول اسكي ) ) او استخدم ثوابت الويندوز api اذا كنت تعرف .
    البارمتر الثاي الاحداثي السيني للماوس لحظة ضغط الزر
    البارمتر الثالث الاحداثي الصادي للماوس لحظة ضغط الزر .


    تطبيق عملي ..

    اضف هذه الدالة
    void key_1(unsigned char key, int x, int y )
    {
            if(key == 27 )
      exit(0);
    }

    الان ننتقل الى الدالة main
    واكتب هذا ..
            glutKeyboardFunc(key_1);


    الان اذا ضغطت الزر Esc سينتهي البرنامج

    تطبيق على الدالة الاخرى

    static double size =1;

    void SpecialKeys(int key, int x, int y) 
    {
     
            switch(key) {
      case GLUT_KEY_F1 : size++; break;  

      case GLUT_KEY_F2 : size--;if(size==0)size=0;
            }

            glutPostRedisplay();


    }
    واضحة
    اذا ضغط على f1 اضف واحد
    والعكس ..مع f2

    الان سنرسم
            glutSolidTeapot(size);

    الان بالدالة الرئيسية main ضع
            glutSpecialFunc( SpecialKeys);
    وذلك لتفعيل عمل الدالة السابقة

    جرب التطبيق ..


    تنبيه !
    لاحظ في الدالة السابقة الدالة
    glutPostRedisplay();
    هذه الدالة تحدث الرسم ..
    بمعنى انها تمسح اي شيء موجود وتقوم بالابقاء فقط على عمل الدالة render يعني
      glutDisplayFunc(render);
    وبالتالي سيتم تحديث الرسم ...

    بمعنى اخر تقوم باعادة رسم النافذة ... يعني نفس وظيفة الرسالة WM_PAINT الموجودة في دوال API


    التطبيق بالمرفقات ..



    الدرس الرابع :
    التعامل مع الماوس ..


    يوجد عدة دوال منها :
    void glutMouseFunction(void (*func)(int button, int state, int x, int y));
    هذه تطلب منك دالة تحوي على اربع بارمترات
    الاول : اي الازرار تم النقر عليها وهي الاتي /
    GLUT_LEFT_BUTTON
    الزر الايسر
    GLUT_MIDDLE_BUTTON
    الاوسط
    GLUT_RIGHT_BUTTON
    الايمن

    البارمتر الثاني . حالة الزر المضغوط وهو :
    GLUT_DOWN
    يعني الزر تم ضغطه ..

    GLUT_UP
    بعد النقر على الزر يعني رفعت اصبعك منه ... : )

    البارمتر الثالث والرابع الاحداثي السيني والصادي للماوس على التوالي ..

    مثال تطبيقي ..
    void mouse(int button, int state, int x, int y)
    {
            if (button == GLUT_RIGHT_BUTTON)
            {
      if (state == GLUT_DOWN)
            cout << "Right button pressed"
            << endl;
      else
            cout << "Right button lifted "
            << "at (" << x << "," << y
            << ")" << endl;
            }
    }

    اعتقد يشرح نفسه ..

    ثم بالدالة الرئيسة MAIN

            glutMouseFunc(mouse);
    الان جرب ... التطبيق .


    الدالة
    glutPassiveMotionFunc(void (GLUTCALLBACK *func)(int x, int y));
    هذه الدالة سهلة
    تعطيم موقع الفارة فقط

    مثال
    void motionPassive(int x, int y)
    {
            cout << "Mouse moved at "
      << "(" << x << "," << y << ")" << endl;
    }

    ثم تفعلها بالدالة الرئيسية
            glutPassiveMotionFunc(motionPassive);

    --
    الدالة
    glutMotionFunc(void (GLUTCALLBACK *func)(int x, int y));
    هذه الدالة شبيهة بسابقتها
    لكن تقع اذا تم النقر على احد الازرار مع التحريك .. يعني مثل .. شل و حط :)
    drag and drop
    لن نضع عليها مثال ..

    اذا فهمت الدالتين السابقتين ستفهم هذه ايضا

    اولا انظر اي الازرار تم ضغطها وذلك من خلال الدالة
    glutMouseFunc
    وضع متغير مثلا
    اذا تم الضغط على الزر الايسر اجعل المتغير صحيح
    والا اجعله false

    ثم عن طريق الدالة
    glutMotionFunc
    قل ..
    اذا كان المتغير صحيحا .. اعمل كذا
    والا اعمل كذا

    مثال يوضح الفكرة فقط

    bool lbuttonDown;

     if (button == GLUT_LEFT_BUTTON)
            {
      if (state == GLUT_DOWN)
            lbuttonDown = true;
      else
            lbuttonDown = false;
            }

    ثم

    void motion(int x, int y)
    {
            if (lbuttonDown)
      cout << "Mouse dragged with left button at "
      << "(" << x << "," << y << ")" << endl;
    }




    جمعت الدروس في مرفق واحد ..
    والدروس مختصرة وغير منظمة والان مستعجل .. لان صاحب المقهى ازعجني يقول خلص الوقت ..



    بقي مواضيع ما غطيناها .. ممكن في خمس دروس قادمة نغطيها ..

    على فكرة .. تعلم win api اذا كان عندك نية تستمر في برمجة الالعاب تحت الويندوز ..
     
    ملف مرفق(ملفات)
     

    كلمات مفتاحية  :
    دروس مكتبة glut

    تعليقات الزوار ()