عادةً في الألعاب خاصةً الألعاب الثقيلة أو الثلاثية الأبعاديكون هناك العديد من العمليات الحسابية مثل القوانين الفيزيائية التي نجريها عند تصادم الكائنات ببعضها و قوانين سقوط الأجسام و الطيران و غير ذلك أو الذكاء الإصطناعي و التحكم في تصرفات الكائنات الآخرى فضلاً عن إستقبال مدخلات المستخدم و تحليلها و إجراء كل التغيرات , و فوق ذلك كله يأتي عبء الرسم و إجراء قوانين رسم المنظور و عمل كل التأثيرات المطلوبة في الرسم. و نحن نريد أن يتم ذلك كله في جزء بسيط من الثانية حتى يكون تظهر اللعبة و كأنها لقطة فيديو أو كائنات متحركة بالفعل و ليس مجموعة من الصور التي تعرض الواحدة تلو الآخرى. يمكن أن نتكفل على قدر ما نستطيع و على قدر خبراتنا المتواضعة بعمل خوارزميات سريعة للقيام فكل القوانين الفيزيائية و غيرها و إدارة الذاكرة و التوفيق ما بين الذاكرة و السرعة. و لكن من سيتكفل بعمليات الرسم ؟؟
لماذا OpenGL ؟
إن مشكلة الرسم هي أننا إذا قمنا بالإستعانة بنظام التشغيل لإجراء عملية الرسم فإننا سوف نخسر الكثير من الوقت في ذلك. و هذا لأن نظام التشغيل يقوم بخدمة كل البرامج التي تعمل و لهذا إذا طلبنا منه أن يرسم لنا أي شئ سيقوم بوضع طلبنا في طابور طويل من المهام حتى إذا جاء دورنا يكون قد ضاع جزء كبير من الثانية و هذا ما لا نرضاه. إذاً فلماذا لا نقوم بالرسم وحدنا ؟؟ إن مكتبة الرسوم المفتوحة تقوم بهذا الأمر. إنها تقوم بالوصول المباشر إلى كارت العرض و هذا لتسريع عملية الرسم حتى لا نضطر إلى الوقوف في الطابور. و لم تتوقف مكتبة الرسوم المفتوحة عند هذا الحد , بل إنها قد قامت بتوفير العديد من الدوال التي تساعدنا في عمل التأثيرات المطلوبة بسرعة. حتى إن أوامر دوران الكائنات فيها أسرع من عمل ذلك بإستعمال الدوال المثلثية sin و cos. إذاً فنحن أما صرح عظيم مليء بالدوال التي تساعدنا في تسريع عملية الرسم بل و في القيام بالعديد من التأثيرات مثل عمل الضوء و تدريجات الألوان و الشفافية و رسم المنظور.
مكتبات إنشاء الواجهات رسومية
قد يتسائل البعض كيف سنستعمل لغة C في برمجة ألعاب بها رسوميات و نحن لم نرى في لغة C إلا الشاشة السوداء التي عليها نصوص فقط (أو ما يعرف بالـConsole) ؟ إن هذا السؤال هو لب موضوع الباب. تذكر عندما كنت مبتدئاً في لغة C ألم تكن تستخدم مكتبات مثل stdio.h و stdlib.h و math.h و غيرها ؟ هذا ما سوف نفعله عندنا نقوم بعمل واجهات رسومية و إنشاء نوافذ.إن هناك العديد من المكتبات التي تتيح لنا إنشاء واجهات رسومية و ليس مكتبة واحدة. إذا كنت في نظام ويندوز لديك مكتبةwindows.h بها دوال و تصنيفات لإنشاء واجهات رسومية و التعامل مع مؤشر الفأرة و غير ذلك. كما أن في لينوكس عندنا عدد غفير من مكتبات إنشاء الواجهات الرسومية مثل Gtk التي تستخدم لإنشاء نوافذ متوافقة مع واجهة Gnome و مكتبة Qt التي ننشئ بها نوافذ متوافقة مع واجهة Kde. كما أن مكتبة Qt موجوده على أغلب أنظمة التشغيل مثل ويندوز و ماك. فيمكنك من خلال إستخدام مكتبة Qt أن تقوم بكتابة كود لبرنامج معين مرة واحدة ثم تترجمه على نظام لينوكس ثم تذهب إلى الويندوز و تترجمه هناك أيضاً ثم تذهب إلى ماك و تترجم نفس البرنامج على ماك و الكود كما هو لا يتغير. فيكون عندك نسخة لنفس البرنامج تعمل على لينوكس و نسخة آخرى تعمل على ويندوز و آخرى تعمل على ماك. و هذا بالطبع يؤدي نفس الغرض الذي من أجله خرجت الجافا حيث تكتب الكود مرة واحدة و يعمل على أنظمة مختلة إلا أنك ستكلف نفسك القليل من الجهد في ترجمة الكود عدة مرات على أنظمة مختلفة. و من البرامج التي كتبت بمكتبة Qt برنامج Google Earth الشهير. و من ضمن المكتبات التي تنشئ نوافذ و واجهات رسومية مكتبة Glutالتابعة لمكتبة الرسوم المفتوحة. حيث إن مكتبة الرسوم المفتوحة OpenGL مكونة من عائلة كبيرة من المكتبات كل واحدة لها غرض معين. فعندنا مكتبة Gl و وظيفتها أنها تقوم بعمليات الرسم الأولية فقط , و هناك مكتبة آخرى إسمها Glu (إختصار لكلمةGraphics Library Utilities) مبنية على Gl تقوم بعمليات رسم متقدمة و ترسم المنظور و بعض الأشكال الثلاثية الأبعاد.و مكتبة Glut هي إختصار لكلمة Graphics Library Utilities Toolkit و هي مختصة في عملية إنشاء النوافذ و التحكم في الزمن و التعامل مع مدخلات المستخدم و بها بعض الدوال المتخصصة في رسم بعض الأشكال الثلاثية الأبعاد. و هناك مكتبة آخرى إسمها Glui و هي إختصار لكلمة Graphics Library User Interface و هي مبنية على مكتبة Glut و تقوم بإنشاء مكونات على النافذة مثل الزر و مربع النصوص و غير ذلك. و تلك المكتبات هي الآخرى موجودة على أكثر نظم التشغيل فتقوم بكتابة الكود مرة واحدة فقط ثم ترجمته على مختلف أنظمة التشغيل. و إن شاء الله سوف نشرح على مكتبة Glut.
قبل أن نبدأ :
قبل أن نبدأ بشرح أساسيات مكتبة جلوت لإنشاء واجهة رسومية يجب أولاً أن نحضر المكتبات و الملفات المرجعية التي سنقوم بإستخدامها.بمعنى أن هناك بعض الملفات التي يجب أن تتوفر عندنا (مثل ملفات الـDLL) حتى تعمل التطبيق الذي فيه مكتبة جلوت و مكتبة الرسوم المفتوحة.
إذا كنت تستعمل نظام لينوكس يجب عليك أن تقوم بتنزيل الحزم glutg3 و libglut3 و libglut3-dev و ذلك حتى تعمل مكتبة جلوت عندك كمبرمج. أما عندما تنشر لعبتك التي أنجزتها بمكتبة جلوت يجب أن تكون تلك الحزم عند من سيلعب اللعبة (طبعاً تتوفر تلك الحزم بالإضافة إلى إعتمادياتها). إذا كنت سوف تقوم بالترجمة عن طريق سطر الأوامر إكتب:
g++ -lglut CODE-FILE.cpp -o EXEC-FILE
و إذا كنت تستخدم أي من بيئات البرمجة المتكاملة IDEs (مثل الـCode Blocks و الـMono Develop) يجب أن تقوم بإضافة مع الملفات المرجعية و تضيف الملف libglut.a الموجود في مجلد /usr/lib/ , ففي برنامج Mono Develop بعد أن تقوم بإنشاء مشروع جديد New Solution إذهب إلى قائمة Project ثم إلى Options ثم ستظهر لك نافذة فيها قائمة على اليسار , إذهب إلى Configurations ثم Debug (أو Release) ثم حدد بعد ذلك إختيار Code Generation. و منه ستجد قائمة فارغة بيضاء , هذه القائمة هي التي يجب أن تضع فيها المكتبات التي تريد أن تلحقها بالمشروع.إضغط على كلمة Browse ثم إدخل إلى مجلد /usr/lib/ و إبحث عن ملف libglut.a ثم قم بتحديده. و هكذا بعد أن تنتهي يصبح المشروع الذي أنشأته مستعداً لكي يعمل مع مكتبة جلوت.
هناك شئ آخر سوف نحتاج إليه في الفصل القادم و سوف نقول لماذا سنحتاجه الآن. و هو هل عندما نترجم اللعبة و نشغلها ستخرج لنا شاشة سوداء Console رغم أننا قد قمنا بإنشاء نافذة ؟ هذا الأمر يعتمد على خيارات المشروع الذي نقوم بإنشاءه. تحت خيارCode Generation ستجد خيار آخر إسمه Output و فيه ستجد مربع مكتوب عليه Run on External Console. إذا قمت بتحديدها فسوف يخرج لنا عند تشغيل البرنامج نافذة Console. سوف تفيدنا هذه النافذة فيما بعد عن إجراء إختبارات في الكود. مثلاً نريد أن نقوم بحساب سرعة تنفيذ إحدى الأكواد و نحو ذلك و نريد أن نخرج بعض الأرقام على الشاشة عن طريق الأمر printf. عندها سنقوم بمراقبة نافذة سطر الأوامر التي ستخرج لنا لمشاهدة أي شئ نريد تجربته. و في الفصل التالي سنحتاج إلى هذا الأمر.

إذا كنت تستعمل نظام ويندوز فإنه في الغالب سيكون ملف gl.h و glu.h موجودان عندك في مجلد المترجم الذي تستعمله أماglut.h فيجب أن تقوم بتوفيره بنفسك. قد أولاً بتحميل حزمة مكتبة جلوت بمشتمالتها التي تحتوي على الملفات الرأسية و الملفات المرجعية ذات إمتداد lib و ملفات الـDLL. قم مثلاً بتحميل الحزمة عن طريق هذا الرابط:
http://www.xmission.com/~nate/glut/glut-3.7.6-bin.zip
ثم قم بوضع كل ملف في مكانه. عندك ملف glut.h ستقوم بوضعه في مجلد GL الموجود بمجلد include الموجود بالمجلد الرئيسي للمترجم الذي تعمل عليه. و عندك ملف إسمه glut32.dll سوف تقوم بوضعه إما في مجلد system32 الموجود في مجلدwindows أو أنك تضعه بجانب الملف التنفيذي exe حيث أن المستخدم ليس عنده هذا الملف في نفس المجلد. ثم قم بربطه بالمشروع الذي نقوم بإنشائه كما رأينا في طريقة لينوكس. فمثلاً إذا كنت تستعمل بيئة Visual C فيكفيك أن تقوم بوضع ملفglut32.lib في المجلد Lib المخصص لكل تلك الملفات المرجعية. مثلاً إذا كنت تستعمل CodeBlocks إذهب إلى قائمةproject ثم Build options ثم إختر Linker settings و ستظهر لك قائمة إسمها Link Libraries. قم بوضع فيها الملفات glut32.lib و opengl32 و glu32 (إذا كنت سوف تستعملها أصلاً). و تذكر أنه يجب عليك أن توفر للمستخدم ملف glut32.dll و glut32.lib بجانب الملف التنفيذي. أو هناك حل آخر ألا و هو أنك إذا قمت بعمل ملف تثبيت setup file بعد الإنتهاء من اللعبة يمكنك أن تجعله يضع ملف glut32.dll في مجلد system32 بنفسه.
إنشاء نافذة بمكتبة جلوت:
و الآن سوف نبدأ في كتابة أول برنامج لنا بإستعمال مكتبة جلوت. سيقوم هذا البرنامج بإنشاء نافذة عادية جداً. و هذا لكي تتعلم ببساطة كيفية إنشاء نوافذ عن طريق مكتبة جلوت. قم بتضمين الملفات الآتية: GL/gl.h و GL/glut.h و GL/glu.h إذا كنت ستستخدم تلك المكتبة. طبعاً ستحتاجها حتماً في الألعاب الثلاثية الأبعاد. في المثال الأول لن نحتاج لمكتبة glu. و الآن نبدأ بكتابة أول برنامج لنا بمكتبة جلوت .. في بداية أي برنامج يستعمل تلك المكتبة إبدأ بهذا السطر:
glutInit(&argc,argv);
و هذان المتغيران argc و argv هما البارمترات الرئيسية التي تمرر للدالة الرئيسية main عندما نقول:
int main (int argc, char** argv)
فإن المتغير الأول يعبر عن عدد البارامترات التي مررت إلى البرنامج و المتغير الثاني هو مصفوفة لسلسلة حرفية string فيها البارامترات التي تم تمريرها. ثم نقوم بتحديد نمط العرض. مثل تحديد نمط الألوان بRGBِA أي اللون الأحمر و الأخضر و الأزرق هي الألوان الأساسية ثم بخلطها و تحديد نسبها يتم التلوين ثم قيمة ِAlpha التي تحدد درجة شفافية اللون. فقد يكون اللون شفافاًُ تماماً إذا كانت قيمته صفر. إنظر إلى هذا السطر:
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA);
هنا قمنا بتحديد بعض أنماط العرض مثل إستخدام الألوان RGBA و إستعمال بيانات من نوع double لحفظ بيانات الرسم. ثم نقوم بتحديد المكان الذي نريد أن نضع فيه النافذة و حجم هذه النافذة. ثم نقوم بإنشائها و إعطائها عنواناً لكي يظهر في شريط عنوان النافذة. و يمكننا كذلك أن نجعل النافذة تملأ الشاشة كلها مهما كانت إستبانتها:
glutInitWindowPosition(200,200);
glutInitWindowSize(320,320);
glutCreateWindow(“My First Window !!”);
هنا إنتهينا من إنشاء النافذة. فيكون الكود الذي وضعناه هكذا:
#include <GL/glut.h>
int main (int argc , char** argv)
{
glutInit(&argc,argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA);
glutInitWindowPosition(200,200);
glutInitWindowSize(320,320);
glutCreateWindow(“My First Window !!”);
return 0;
}
جرب أن تقوم بترجمة هذا الكود بعد أن تقوم بربط البرنامج بملف مكتبة جلوت و تقوم بالذي ذكرناه في البداية ثم قم بترجمة الكود و إنظر إلى النتيجة. ستجد أن البرنامج قد إنغلق مباشرةً بعد إنشاء النافذة. و السبب هو أن البرنامج كما نرى يقوم بإنشاء النافذة ثم ينتهي الكود بعد ذلك. و الحل هو أن نضع في آخر سطر في الكود هذا السطر:
glutMainLoop();
حيث سيتم عمل حلقة تكرارية تنتظر المدخلات من المستخدم و هذا سوف يبقى النافذة مفتوحة حتى يغلقها المستخدم بنفسه. جرب إضافة هذا السطر ثم إنظر إلى النتيجة. ستجد أن النافذة قد تم إنشائها بالفعل و في المكان المحدد و بالحجم الذي ذكرناه و لكن النافذة ستجد أن خلفيتها أخذت صورة من التطبيق الذي تحتها. مثل هذه الصورة:
و السبب هو أننا لم نقم بذكر أي شئ عن خلفية النافذة التي أنشأناها , فقط ذكرنا بيانات النافذة التي تختص بالإطار فقط و ليس الخلفية , لذلك لم يقم بتلوين أي شئ في الخلفية. و ليس هناك لون إفتراضي لها. هنا يأتي دور مكتبة الرسوم المفتوحة OpenGL. في المثال السابق لم نقم بتضمين إلا ملف GL/glut.h أما في المثال التالي سنحتاج إلى تضمين ملف GL/gl.h و سنقوم بتحديد لون الخلفية عن طريق هذا الأمر:
glClearColor(1,1,1,1);
هنا قد إخترنا اللون الأبيض كلون للخلفية و إذا أردنا اللون الأحمر نمرر للدالة 1 ثم صفرين ثم 1 , فالبارامتر الأول يشير إلى نسبة اللون الأحمر و الثاني للأخضر و الثالث للأزرق و الرابع للشفافية و يمكنك كذلك أن تدخل بعض الأزرق فتمرر 1 و صفر و 0.5 و 1. أي أنه يمكنك أن تتحكم بالنسب كيف تشاء. إذا إقتصرت على إضافة هذا السطر فإنه لن يغير في البرنامج شيئاً. بهذا السطر قد حددت لون الخلفية فقط و لكنك لم تقل له نظف النافذة أو إرسم أي شئ. و هنا نعود لمكتبة جلوت مرة آخرى حيث سنجد أنها توفر لنا ميزة و هي أنها تجعلنا نقوم بعمل بعض الدوال التي تستقبل بعض المتغيرات التي تدل على تغير معين حدث .. للمزيد من التوضيح يمكنك عمل دالة بهذا الشكل:
void DummyFunction()
{
/*قم بما تريد فعله*/
}
ثم تخبر مكتبة جلوت بأنك تريد أن تستدعي هذه الدالة في حالة كذا و كذا. فستقوم في الدالة الرئيسية بكتابة كود مثل هذا السطر:
glutDisplayFunc(DummyFunction);
هكذا تكون قد أخبرت مكتبة جلوت بأن تستدعي هذه الدالة في حال حدوث تغير على النافذة يحتاج إلى إعادة الرسم. مثل أن يقوم المستخدم بعملMinimize للنافذة ثم Restore فهكذا سنفقد الرسمة التي كانت موجودة على النافذة لهذا سنحتاج إلى إعادة رسمها. و كذلك إذا جائت نافذة آخرى فوق نافذتنا ثم إنصرفت. أيضاً سنفقد الرسمة التي كانت فوق النافذة. فهنا نخبر مكتبة جلوت باننا نريد أن نقوم بإستدعاء الدالة التي أسميناها DummyFunction إذا ما تطلب الأمر إعادة رسم محتويات النافذة. و هذا بالضبط ما نريده لعمل خلفية للنافذة. سنقوم في هذه الدالة التي أنشأناها بإعادة تلوين الخلفية. قم بعمل تلك الدالة:
void Display()
{
glClear(GL_COLOR_BUFFER_BIT);
/*أوامر الرسم توضع في هذا المكان*/
glFlush();
glutSwapBuffers();
}
هكذا نكون قد إنتهينا من إعادة تلوين الخلفية. في الدالة الأولى التي إستدعيناها قلنا له قم بتلوين خلفية النافذة. طبعاً سوف يقوم بتلوين الخلفية باللون الذي إتفقنا عليه في البداية في الدالة الرئيسية بعد أن قمنا بإنشاء النافذة. و السطران الآخران يقولان أننا قد إنتهينا من تحديد ماذا نريد رسمه ليذهب به بعد ذلك إلى عمليات تصيير الرسم في مكتبة الرسوم المفتوحة ثم إلى كارت العرض ليتم عرضه. طبعاً عندما نريد أن نرسم إي شئ آخر كما سنشرح لاحقاً سنقوم بكتابة كل أوامر الرسم بين الدالة الأولى و الدالتان الآخرتان. و الآن لا ننسى أن تخبر مكتبة جلوت بأن تقوم بإستدعاء تلك الدالة إذا ما تغير شئ في النافذة يتطلب إعادة الرسم فنقول:
glutDisplayFunc(Display);
و يكون الكود في النهاية بهذا الشكل:
#include <GL/gl.h>
#include <GL/glut.h>
void Display()
{
glClear(GL_COLOR_BUFFER_BIT);
glFlush();
glutSwapBuffers();
}
int main(int argc , char** argv)
{
glutInit(&argc,argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA);
glutInitWindowPosition(200,200);
glutInitWindowSize(320,320);
glutCreateWindow(“My First Window !!“);
glClearColor(1,0.4,0,1);
glutDisplayFunc(Display);
glutMainLoop();
return 0;
}
جرب تطبيق هذا الكود و سترى أن النافذة خرجت بهذا الشكل كما في الصورة:
حيث أنه قد تم تلوين النافذة باللون الذي طلبناه في الدالة الرئيسية و تم إستدعاء الدالة التي أنشأناها و أسميناها Display و في تلك الدالة قلنا بأننا نريد أن ننظف النافذة و تنظيف النافذة يكون بمسح كل ما عليها و تلوينها بلون الخلفية الذي طلبناه ثم قلنا له بأننا أنهينا الرسم. و هكذا ظلت مكتبة جلوت تستدعي تلك الدالة كلما تطلب الأمر إعادة الرسم. أحياناً في الألعاب نريد أن يتم إعادة رسم محتويات النافذة عدة مرات في الثانية الواحدة. و دالة glutDisplayFunc لا تفي بالغرض إذ أنها تستعدي دالة إعادة الرسم إذا ما تم مثلاً تصغير النافذة أو تكبيرها أو وضع نافذة آخرى فوقها. أما في الألعاب فلن نقول مثلاً بتغيير حجم النافذة طوال اللعبة حتى نرى آخر التطورات التي تحدث في اللعبة. فنريد أن نقول لمكتبة جلوت أننا نريد أن نستدعي دالة العرض بإستمرار و ليس في حالة حدوث تغير على النافذة. فنقول:
glutDisplayFunc(Display);
glutIdleFunc(Display);
فالسطر الثاني يقول لمكتبة جلوت إستدعي دالة العرض في حالة سكون البرنامج. و هذا سيجعل دالة العرض تنفذ بإستمرار. و هناك عدة طرق لجعل تحديث الرسم مستمر طوال البرنامج غير هذه الطريقة سنذكرها مؤخراً إن شاء الله.
البدء بالرسم مكتبة الرسوم المفتوحة:
الآن نريد أن نقوم بالرسم فعلياً. نريد أن نرسم مثلثات و مربعات و خطوط و دوائر و غير ذلك و نريد أن نلون تلك الأشياء. طبعاً سيتبادر إلى الذهن أننا سنقوم بذلك في دالة العرض التي أسميناها Display. و الإسلوب الذي تتبعه مكتبة الرسوم في الرسم هو أنها تحتفظ بلون معين للرسم في ذاكرتها. تخيل مثلاً أنك معك فرشاة و اللون الإفتراضي الذي تحمله هذه الفرشاة مثلاً هو اللون الأسود. فإذا ما جئت لتلون بها ستحصل على اللون الأسود إلا إذا قلت أنك تريد أن تغير اللون و هذا ما يحدث في مكتبة الرسوم المفتوحة. فاللون الإفتراضي هو الأسود و إذا قمت برسم أي شئ ستحصل على اللون الأسود إلا أنه يمكنك أن تقوم بتغيير اللون وقتما تشاء. كذلك فإن في مكتبة الرسوم المفتوحة تذكر أولاً ما الشكل الذي تريد رسمه ثم تقوم بذكر أماكن النقاط ثم تقول أنك إنتهيت من رسم ذلك الشكل. و خذ هذا الكود على سبيل المثال في دالة العرض:
void Display()
{
glClear(GL_COLOR_BUFFER_BIT);
glBegin(GL_TRIANGLES);
glColor3f(1.0,0.0,0.0); glVertex2f(0.8, 0.8);
glColor3f(0.0,0.5,1.0); glVertex2f(0.6, -0.5);
glColor3f(1.0,1.0,0.0); glVertex2f(-0.5, 0.0);
glEnd();
glFlush();
glutSwapBuffers();
}
هنا في دالة glBegin قلنا أننا نريد أن نرسم مثلثات. و يحتاج المثلث إلى ثلاث نقاط لتعريفه. في البداية قمنا بتغيير اللون ثم ذكرنا نقطة من النقاط. طبعاً في دالة glVertex2f قمنا بتمرير قيمتين. الأولى للإحداثة س و الثانية ص. أو x و y. حيث تشير القيمة صفر و صفر إلى منتصف النافذة و القيمة 1 و 1 إلى شمال شرق النافذة و القيمة -1 و -1 إلى جنوب غرب الشاشة و هكذا. قمنا بتحديد ثلاث نقاط على النافذة و لاحظ أننا غيرنا اللون عند كل نقطة لذلك سنجد عندما نقوم بتشغيل البرنامج أن المثلث فيه تدريجات ألوان. لقد قمت بتغيير لون الخلفية و جعلته اللون الأسود أي القيم صفر و صفر و صفر و واحد. ثم قمت بترجمة البرنامج فصار كهذا الشكل:
طبعاً يمكنك أن ترسم أي شكل و أي شئ تريده. جرب مثلاً في دالة glBegin أن تضع بعض الأشكال الآخري مثل GL_QUADS حيث ستذكر لها أربع نقاط عن طريق دالة glVertex2f. و يمكنك أن تعمل glBegin لمضلع متعدد النقاط فتقول GL_POLYGONS ثم تذكر أي عدد من النقاط. جرب مرة أن تغير اللون و جرب أن لا تغير اللون و جرب العديد من النقاط و الألوان و جرب أن ترسم عدة أشكال. فمثلاً عندما تنتهي من رسم إحدى الأشكال و تستدعي glEnd قم بعمل glBegin مرة آخرى و إرسم شكل آخر ثم glEnd لتنتهي من رسم ذلك الشكل الآخر و هكذا. ولا تنس ان تستدعي دالة glFlush و glutSwapBuffers في نهاية دالة العرض.