abshammeri

دروس حول مكتبة glut ..

10 ردود في هذا الموضوع

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

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

ماذا تعني ..وبماذا تفيدنا هذه المكتبة ؟

تستخدم لبناء النافذة وربطها بOPENGL

تستخدم للادخال ... يعني للتعامل مع رسائل الماوس والكيبورد وعصا الالعاب ..

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

تعمل على عدد من الانظمة ..

هذه الدروس مقتبسة من عدد من الدروس المتناثرة .. اقول مقتبسة وليس مترجمة ..

مثلا

http://www.lighthouse3d.com/opengl/glut/

ماذا عن دوال Win Api ?

مميزة ومفيدة ..

لكن قد تكون اصعب ( او اقول ) طويلة نوعا ما ..

في دروس NEHE المستخدم هو دوال WIN API ..

طبعا WIN API تعطيك كل شيء ..

لكن GLUT تسهل حياتك البرمجية .. باكوادها المختصرة .

ايهما اتعلم .. GLUT .. او ..WIN API ?

النتيجة واحدة ... الغرض من تلك المكتبات بالنسبة لنا .. ربط OPENGL بالنافذة ..والتعامل مع الكيبورد والماوس .. وهذا ماتفعله المكتبتان ..

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

اين اجد هذه المكتبة "GLUT" ؟

حمل من هنا

http://www.xmission.com/~nate/glut/glut-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

لاحظ الصورة

01_09_05_02_45_06_1125567906aa.JPG

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

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

التعبير هذا تقريبي .. لتوضيح المفهوم ..

الان سنستخدم 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 tutrials.zip

تم تعديل بواسطه الشمري
0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

ممتاز ! !

انتظر تعليق علي الدروس بعد قرائتها

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

ننتظر :)

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

نكمل بعون الله .

الدرس الخامس: الانيمشن ...

يعني نريد استخدام مؤقت .. ما

بينما اكتب هذا الدرس .. اشعر بعدم الاقتناع :( .. لان هذه الطريقة فيها كم ؟؟؟ .. لا اريد تشتيك الان ..

افرض انك تريد تدور المجسم كل فريم 45 درجة ..

اذا : يجب ان تستدعي دالة التصيير render كل مرة ..

نستخدم الدالة :

glutIdleFunc(void (GLUTCALLBACK *func)(void));

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

نحن سنضع الدالة render هي المقصودة .

لاحظ

  long loop =0;

void render(void)
{
 loop++;

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

glPushMatrix();

glTranslatef(0,0,-12);
glRotatef(loop,0,1,0);

glutSolidTeapot(1);

glPopMatrix();

 glutSwapBuffers();

}

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

glutIdleFunc(render);

الشرح :

ببساطة قمنا بتعريف متغير .. وقلنا نريد ان نزيد قيمته كل مدة معينة بمقدار ..واحد.. ++ ..

الان الدالة

glutIdleFunc(render);

تقوم باستدعاء الدالة render كل مرة .. وبالتالي سيزيد loop كل مرة بمقدار ...

واستخدمنا دالة التدوير glRotatef .. لتدوير الجسم ..

تنبيه !

الدوال

glPushMatrix

glTranslatef

glRotatef

glPopMatrix

خاصة بopengl وبالتالي لا مجال لشرحها هنا .

لكن سنوضح ماحدث بشكل مبسط

الدالة

glRotatef تدور الجسم

glTranslatef تزيح الجسم

glPushMatrix

glPopMatrix

تحفظ قيم المصفوفة (مصفوفة الازاحة او التدوير او اي مصفوفة (

يعني لو قلت

	glRotatef(loop,0,1,0);

glutSolidTeapot(1);

glutSolidTeapot(2);

هنا الجسم الاول والثاني كلهم رح يدوروا .. وهذا في الغالب لانريده

الحل

glPushMatrix();
glRotatef(loop,0,1,0);

glutSolidTeapot(1);
glPopMatrix();


glutSolidTeapot(2);

الان الجسم الاول هو الذي سيدور ..

اذا لم تفهم ما عليك ..

هذه امور تخص opengl .. لكن ذكرناها هنا لنوضح عمل الدالة

glutIdleFunc

-------------------------

الدرس السادس :

القائمة .. وكيفية عملها ..

يعني رح نسوي Menu .. اي نعم .. menu مرة وحده .

الدالة

int glutCreateMenu(void (*func)(int value));

هذه تقوم بربط القائمة بدالة معينة للتعامل مع الاحداث .. لاحظ انها تطلب منك دالة لها بارمتر واحد ..

هذا البارمتر هو المعرف لكل قائمة .. ID

مثلا

عندك القائمة FILE معرفها مثلا 222

القائمة EXIT معرفها مثلا 5432

وهكذا ...

طبعا انت تختار اسم القائمة .. وكل شيء .. ذاك مثال فقط

سترى ... لاتستعجل .

الدالة

glutAddMenuEntry(const char *label, int value);

هذه الدالة تضيف قائمة

تطلب منك دالة

هذه الدالة لها بارمترين

الاول اسم القائمة اللي يحبه قلبك

الثاني معرف هذه القائمة .. اختر اي رقم .. يعني فقط كمعرف .. اهم شيء تختلف الارقام بين قائمة واخرى

الدالة :

glutAttachMenu(int button);

هذه الدالة تقولك ..

متى تريد القائمة ان تنبزغ ><<< صح تنبزغ ..:)

اذا ضط الزر الايمن او الايسر او الاوسط او الوسطي او اللي في النص ..

انت تضع في البارمتر النوع المطلوب

وهي :

GLUT_LEFT_BUTTON

GLUT_MIDDLE_BUTTON

GLUT_RIGHT_BUTTON

تطبيق عملي ..

بدل من تكويم الدوال في الدالة main سنقوم بـوضع دالة خاصة بالقوائم .. نسميها مثلا arab_menu

ودالة ثانية للتعامل مع الرسائل التي تصل الى القائمة .. (الخاصة بـ glutCreateMenu)

انظر

   static float size =1; 

void processMenuEvents(int option)
{

switch (option)    
{  case 1 :
   size-=.1;
 break;
 case 2 :
   size+=.1;

}

  glutPostRedisplay();
}



void arab_menu() {

 

 
  glutCreateMenu(processMenuEvents);

 
glutAddMenuEntry("small",1);
glutAddMenuEntry("big ",222);
 
 
glutAttachMenu(GLUT_RIGHT_BUTTON);
}

الامر جدا سهل ..

اولا انشأنا القوائم

glutAddMenuEntry("small",1);
glutAddMenuEntry("big ",222);

القائمة الاولى سميناها .. صغير .. واعطيناه id .. يعني رقم خاص به ليكون رمز التواصل بيننا وبين تلك القائمة

والاخر big .. واعطيناه ID

متى ستظهر القائمة ؟؟

الجواب

glutAttachMenu(GLUT_RIGHT_BUTTON);

اذا تم الضغط على الزر الايمن

اين تلك الدالة التي تقوم بالتعامل مع رسائل القائمة

يعني اذا تم اختيار القائمة االولى او الثانية ماذا سيحدث ..

الجواب

glutCreateMenu(processMenuEvents);

يعني نريد ان نجعل الدالة processMenuEvents ذات البارمتر الواحد هي المسؤولة عن التعامل مع الرسائل ..

 void processMenuEvents(int option) 
{

switch (option)    
{
 case 1 :
   size=0.5;
 break;
 case 222 :
   1.5;
 break;
}

 
}

اذا كان المعرف هو ذو الرقم واحد اي الخيار SMALL فغير قيمة المتغير size

واذا كان المعرف 222 الخاص بالخيار big فغير قيمة size الى 1.5

الان نستدعي الدالة arab_menu في الدالة main .. عشان تعد لنا القائمة واحداثها ..

التطبيق سهل جدا .

حاول تكتبه مرة واحدة وسترى مدى سهولته ..

القائمة ,, قد تبدو غامضة في البداية .. لكن اتقانها امؤ في غاية البساطة ..

لاتنسخ الاكواد .. اكتبها .

--------------------

اعدام النافذة ..

حلوة اعدام .. بس تعبير حلو ..

يعني عندك نافذة .. سويتها .. وش لون تحذفها ..

اولا لاحظ في الدرس لسابق

	int menu;

   menu = glutCreateMenu(processMenuEvents);

الدالة تعيد قيمة ... وهي تمثل القائمة ..خزناه في متغير ..(( لابد ان يكون المتغير عام حتى نتحكم فيه ))

الان لنعدم هذه القائمة

glutDestroyMenu(menu);

هل يوجد اسهل من كذا ..

بس لاتحذفها الا اذا كنت لست بحاجة اليها ..

-------------------

الدرس السابع :

اضافة قائمة فرعية sub-menu

الامر سهل جدا ..

ماذا فعلنا في الدرس السابق

	int menu;

   menu = glutCreateMenu(processMenuEvents);

////add menu \\\\

glutAddMenuEntry("small",1);
glutAddMenuEntry("big",222);
 
 
glutAttachMenu(GLUT_RIGHT_BUTTON);

الان

	int menu,menu_2;

   menu = glutCreateMenu(processMenuEvents);

////add menu \\\\
glutAddMenuEntry("small",1);

menu_2 = glutCreateMenu(processMenuEvents);
glutAddSubMenu("sub-menu",menu);



glutAddMenuEntry("big",222);

 
 
glutAttachMenu(GLUT_RIGHT_BUTTON);

قلنا انشئ قائمة

وضع فيها small ....

انشئ قائمة اخرى واضف لها قائمة متفرعة

menu_2 = glutCreateMenu(processMenuEvents);
glutAddSubMenu("sub-menu",menu);

القائمة المتفرعة تحتوي على القائمة menu

يعني كل ما يقع تحت الدالة

menu = glutCreateMenu(processMenuEvents);

سيعتبر قائمة فرعية لـ

glutAddSubMenu("sub-menu",menu);

الامر واضح فقط تركيز ..

الان مارأيك لو ننشئ قائمة فرعية من قائمة فرعية

هكذا

	int menu,menu_2,menu_3;

   menu = glutCreateMenu(processMenuEvents);

////add menu \\\\
glutAddMenuEntry("small",1);

menu_2 = glutCreateMenu(processMenuEvents);
glutAddSubMenu("sub-menu",menu);


menu_3 = glutCreateMenu(processMenuEvents);
glutAddSubMenu("sub-sub-menu",menu_2);

فقط حاول ....

-----------------

الدرس الثامن :

التعديل على القوائم ... (جمع قائمة) :rolleyes:

يعني تضيف خيار اثناء وقت التشغيل .. او تحذف خيار ما .. او تبدل ترتيب الخيارات

قد يكون هذا الدرس غير مهم .. الا انه مفيد بكل الاحوال . .

اولا انشأنا قائمة كما في هذه الصورة ..

نريد ان نغير ترتيب الخيارات هكذا ..

كيف يمكننا عمل ذلك ..

الجواب :

باستخدام

void glutChangeToMenuEntry(int entry, char *name, int value);

هذه الدالة تغير ترتيب القوائم ..

البارمتر الاول .. ترتيب الخيار الذي تريده .. هل تريده الاول اذا تكتب واحد او الثاني ..2 .. او الثالث ..3 .. الخ

البارمتر الثاني اسم الخيار ... مثلا في مثالنا السابق small

البارمتر الثالث : معرف الخيار ..id .. الرقم الذي وضعته للخيار .

مثال :

انشأنا قائمة كما في المثال السابق

void arab_menu() 
{

int  menu = glutCreateMenu(processMenuEvents);

////add menu \\\\
glutAddMenuEntry("small",1);
   glutAddMenuEntry("big",222);

glutAttachMenu(GLUT_RIGHT_BUTTON);
}

الان سنعدل في ترتيب الخيارات

 void processKeys(unsigned char c, int x, int y) {

 switch (c)
 {
 case 'a':
   glutChangeToMenuEntry(2,"small",1);
   glutChangeToMenuEntry(1,"big",222);
   break;
 case 'b':    
   glutChangeToMenuEntry(1,"small",1);
   glutChangeToMenuEntry(2,"big",222);
   break;
 }
}

كما تلاحظ .. دالة استقبال رسائل الكيبورد .. التي تعلمناها في الدرس الثالث على ما اذكر .

قلنا اذا كان الزر المضغوك هو a

قم بتبديل الخيارات

glutChangeToMenuEntry(2,"small",1);
glutChangeToMenuEntry(1,"big",222);

قلنا الخيار small الذي معرفه الرقم 1 .. اجعل ترتيبه الثاني

الخيار big الذي معرفه الرقم 222 اجعل ترتيبه الاول

اما اذا كان الزر المضغوط b

glutChangeToMenuEntry(1,"small",1);
glutChangeToMenuEntry(2,"big",222);

عكس العملية السابقة ..

المثال بالمرفقات

--------

الان سنحذف خيار ......

glutRemoveMenuItem(int entry);

نمرر لها ترتيب الخيار .. هل هو الخيار الاول او الثاني او الثالث .. الخ

مثال /

نفس المثال السابق سنضيف اليه .

 void processKeys(unsigned char c, int x, int y) {

 switch (c)
 {
 case 'a':
   glutChangeToMenuEntry(2,"small",1);
   glutChangeToMenuEntry(1,"big",222);
   break;
 case 'b':    
   glutChangeToMenuEntry(1,"small",1);
   glutChangeToMenuEntry(2,"big",222);
   break;

 case 'r':
 glutRemoveMenuItem(2);break;
 }



}

قلنا اذا ضغط على حرف r احذف الخيار الثاني

glutRemoveMenuItem(2);break;

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

فسيقول مثلا .. الخيار الثاني غير موجود ..

وهذه من ميزات glut ..

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

مثلا ..

الحل مع المشكلة السابقة .. ان تعلم كم عدد الخيارات المتوفرة .. في القائمة ..

وذلك عن طريق الدالة

int  glutGet(GLenum type);

الدالة السابقة عملاقة ..

من اسمها ... تحصل على معلومات عن شيء ما ان تحدده .. مثلا طول الشاشة وعرضها ..

احداثيات النافذة .. طول وعرض النافذة .. نوع العرض او نظام العرض ويسمى display mode ..

لا.. بل وازيدك من الشعر بيت ... :)

تعطيك ال ELAPSED TIME .. الوقت المنقضي ... اذا كنت مبرمج العاب ستعرف قيمة هذا العمل ..

بارمترات الدالة السابقة

GLUT_WINDOW_X

GLUT_WINDOW_Y

GLUT_WINDOW_WIDTH

GLUT_WINDOW_HEIGHT

GLUT_WINDOW_BUFFER_SIZE

GLUT_WINDOW_STENCIL_SIZE

GLUT_WINDOW_DEPTH_SIZE

GLUT_WINDOW_RED_SIZE

GLUT_WINDOW_GREEN_SIZE

GLUT_WINDOW_BLUE_SIZE

GLUT_WINDOW_ALPHA_SIZE

GLUT_WINDOW_ACCUM_RED_SIZE

GLUT_WINDOW_ACCUM_GREEN_SIZE

GLUT_WINDOW_ACCUM_BLUE_SIZE

GLUT_WINDOW_ACCUM_ALPHA_SIZE

GLUT_WINDOW_DOUBLEBUFFER

GLUT_WINDOW_RGBA

GLUT_WINDOW_PARENT

GLUT_WINDOW_NUM_CHILDREN

GLUT_WINDOW_COLORMAP_SIZE

GLUT_WINDOW_NUM_SAMPLES

GLUT_WINDOW_STEREO

GLUT_WINDOW_CURSOR

GLUT_SCREEN_WIDTH

GLUT_SCREEN_HEIGHT

GLUT_SCREEN_WIDTH_MM

GLUT_SCREEN_HEIGHT_MM

GLUT_MENU_NUM_ITEMS

GLUT_DISPLAY_MODE_POSSIBLE

GLUT_INIT_WINDOW_X

GLUT_INIT_WINDOW_Y

GLUT_INIT_WINDOW_WIDTH

GLUT_INIT_WINDOW_HEIGHT

GLUT_INIT_DISPLAY_MODE

GLUT_ELAPSED_TIME

GLUT_WINDOW_FORMAT_ID

الدالة تعيد لك قيمة ماتريد ..

مثلا لو قلت

int num = glutGet(GLUT_WINDOW_X);

ستعيد لك الاحداثي السيني للنافذة ..

الان نريد ان نستفيد منها بمعرفة كم خيار يوجد في القائمة ..

	int num = glutGet(GLUT_MENU_NUM_ITEMS);

واضح ..؟؟

الفائدة .. سنعرف كم عدد الخيارات .. مثلا تريد حذف الخيار الرابع ...

   	 if (num > 4)
     glutRemoveMenuItem(4);

اعتقد واضحة جدا ..

اضافة خيار للقائمة :

void glutAddMenuEntry(const char *label, int value);

تكتب اسم الخيار .. ورقم id الخاص به ..

وسيضاف الخيار ..

مثال

 void processKeys(unsigned char c, int x, int y) {

 switch (c)
 {
 case 'a':
   glutChangeToMenuEntry(2,"small",1);
   glutChangeToMenuEntry(1,"big",222);
   break;
 case 'b':    
   glutChangeToMenuEntry(1,"small",1);
   glutChangeToMenuEntry(2,"big",222);
   break;

 case 'r':
 glutRemoveMenuItem(4);break;
 
 case 'd':
   glutAddMenuEntry("add",681);break;
 }
}

هنا التغيير

case 'd':
glutAddMenuEntry("add",681);break;

اتمنى لك التوفيق ..

الامثلة جمعتها في تطبيق واحد

الدرس التاسع :

اضافة النصوص .. الى تطبيقك ..

تقدم المكتبة glut دوال الخطوط والتعامل معها على طبق من ذهب ..

هناك نوعان من الخطوط .

خطوط الصور ... .. وهذا اسرع Bitmap Fonts

خطوط عادية ... Stroke Fonts وهذه بطيئة ..

ليس المجال هنا لتوضيح مميزات كل نوع ... لان هذا من المفترض ان تعرفه .. اذا تعلمت opengl ..

يعني بعد ان تتعلم opengl .. ستعرف كيف يتم بناء مثل تلك الخطوط .. وما مميزاتها بالتفصيل ..

الخطوط مشكلة ... خاصة في opengl ..

الان سنتعلم كيف ننشئ Bitmap Fonts

void glutBitMapCharacter(void *font, int character)

هذه الدالة ..

البارمتر الاول يأخذ احد الخياررات التالية

GLUT_BITMAP_8_BY_13

GLUT_BITMAP_9_BY_15

GLUT_BITMAP_TIMES_ROMAN_10

GLUT_BITMAP_TIMES_ROMAN_24

GLUT_BITMAP_HELVETICA_10

GLUT_BITMAP_HELVETICA_12

GLUT_BITMAP_HELVETICA_18

بعضها من تقرأها تعرف معناها والبعض الاخر ..يحتاج تفصيل ..

البارمتر الثاني .. مالذي تريد رسمه .. حرف..رقم .. رمز ..

حتى تغير موقع الخط .. نستخدم احد دوال opengl ... ولا مجال لشرحها هنا ..

void glRasterPos2f(float x, float y);
void glRasterPos3f(float x, float y, float z);

كل مايلزمك معرفته .. انها لتغيير الموقع ..

مثال

void render(void) 
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 
glLoadIdentity();
glTranslatef(0,0,-5);

glRasterPos2f(0,0);
glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18,'3');

 glutSwapBuffers();

}

الجديد

glRasterPos2f(0,0);
glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18,'3');

حددنا الموقع وهو بالمنتصف ..

وكتبنا الرقم ثلاثة ,,,

الان هل تريد كتابة كلام كثير ..

الحل .

استخدم for ..

char* string="arab team 2000 ";
char*c;

مصفوفة مؤشرات ( مصفوفة نصية )

glRasterPos2f(0,0);
for (c=string; *c != '\0'; c++)
{

glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18,*c);
}

c=string

يعني اول عنصر في المصفوفة c هو اول عنصر في المصفوفة string وذلك مثل

c =&string[0]

*c != '\0' حتى نصل الى اخر المصفوفة النصية .. null

يعني مادام c لم يساوي null اكمل النسخ ..

glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18,*c);

يعني نرسم الحرف

a

ثم

r

ثم

a

ثم

b

وهكذا حتى نصل الى نهاية المصفوفة النصية وهو

'\0'

التطبيق النهائي

void render(void) 
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 
glLoadIdentity();
glTranslatef(-1,0,-5);

  glRasterPos2f(0,0);

for ( c =&string[0]; *c != '\0'; c++)
{
 
glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18,*c);
}

 glutSwapBuffers();

}

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

---

معرفة عرض الحرف ..

قد تحتاج احيانا لمعرف عرض الحرف .. والفائدة كبيرة ..

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

لكن قد تحتاجها في مسيرتك البرمجية : ) ,,,

int glutBitmapWidth(void *font, int character);

مثال :

glutBitmapWidth(GLUT_BITMAP_TIMES_ROMAN_10 ,'c');

هنا يعطيك عرض الحرف c ..

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

ممكن لاتدرك الفائدة الا بعد ان تواجهك المشكلة .. لاتستعجل :)

الدالة

int glutBitmapLength(void *font, char *string);

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

ممكن تكتب شيء شبيه بالتالي

	unsigned char string[20]="i am muslim"; 
   int length = glutBitmapLength(GLUT_BITMAP_TIMES_ROMAN_10 ,&string[0]);

لم اجربها .. لكن ان شاء الله انها صحيحة ..

الدرس العاشر :

الخطوط من نوع Stroke Fonts

اهم ميزة بها انها من الممكن تصييرها لتصبح 3d font

وايضا يمكنك قلبها .. وتغيير حجمها .. وازاحتها

بينما في الخطوط من نوع Bitmap Fonts لايمكنك الا ازاحتها ..

لكن يجب ان تأخذ في الاعتبار .. ان Stroke Fonts قد تسبب بطأ في لعبتك ..

تحتاج الى دالة واحدة شبيهة بالسابقة

void glutStrokeCharacter(void *font, int character)

البارمتر الاول .. ياخذ

GLUT_STROKE_ROMAN

GLUT_STROKE_MONO_ROMAN

تنبيه !

GLUT_STROKE_MONO_ROMAN له عرض ثابت وهو

104.76 units wide

لا اعرف ماذا تعني هذه الوحدة :P

مثال :

  glPushMatrix();

 glScalef(.1,.1,1);
 glTranslatef(0, 0, -200);
 glutStrokeCharacter(GLUT_STROKE_ROMAN , 'A');
 

 glPopMatrix();

glScalef(.1,.1,1);

هذه تقوم بتغيير الحجم X و Y و Z

ستتعلمها عندما تدخل فيOPENGL

مثال اخر

   char*string="I AM MUSLIM"; 
  char *c;



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



 glPushMatrix();

 glScalef(.1, .1 , 1);
 glTranslatef(0, 0, -300);

 for (c=string; *c != '\0'; c++)
 {
   glutStrokeCharacter(GLUT_STROKE_ROMAN , *c);
 }

 glPopMatrix();



 glutSwapBuffers();

}

مثل المثال السابق في الدرس التاسع

تنبيه ! مكن الممكن انه يوجد الكثير من علامات الاستفهام عند البعض .. بسبب وجود دوال لم يتم شرحها بالتفصيل ... لكن تذكر ان هذه الدروس موجهة لمن يريد تعلم GLUT ...اي دالة تبدأ بـglut هي ما يهمنا ..

---

******** للمتخصصين في opengl فقط ********** الدالة glutStrokeCharacter ترسم خط ... وبالتالي تستطيع التحكم بعرض هذا الخط .. و stipple ايضا , والالوان ..

مثلا

  glLineWidth(2);

او

glColor3f(1,0,0);

او

glLineStipple .....

--

جرب كتابة

  glScalef(.1, -.1 , 2);

او
 glScalef(-.1, .1 , 2);

الخ .,,

وشوف انواع الشقلبات ... :D

:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

الدرس الحادي عشر : متفرقات .,,

كيف تحول النافذة الى ملء الشاشة full screen

glutFullScreen

يجب ان تضع الدالة السابقة بعد صنع النافذة

	glutCreateWindow("arab team - glut  ");
glutFullScreen();

لاخفاء النافذة

glutHideWindow();

ولاظهارها

glutShowWindow();

لاغلاق النافذة

glutDestroyWindow(int window);

حيث تمرر لها قيمة النافذة

مثال

ضع متغير عام

int w ;

اكتب

   w = glutCreateWindow("arab team - glut  ");

ثم اذا ضغط على زر معين

void key(unsigned char s , int x ,int y ) 
{
if (s == 'q') glutDestroyWindow(w);
}

او استخدم الطريقة التقليدية

exit(0);

glutSetWindowTitle(const char *title);

تغير عنوان النافذة

glutSetCursor(2);

تغير مؤشر الماوس .. غير الارقام

الدالة

void glutGameModeString(const char *string);

دالة مهمة .. وتحتاج شوية تركيز

تغير طول الشاشة وعرضها .. ودقة الشاشة الخ

 glutGameModeString("800x600:32");
glutEnterGameMode();

اذا كنت تريد ان تتأكد من ان الدالة ستعمل على جهازك

glutGameModeString("800x600:32");
// enter full screen
if (glutGameModeGet(GLUT_GAME_MODE_POSSIBLE))
 glutEnterGameMode();

اذا اردت المزيد عن هذه الدالة

http://www.lighthouse3d.com/opengl/glut/index.php?gameglut

ستجد الشرح بالتفصيل ..

هذا الدرس لم اضع له مثال بالمرفقات .. ولكن من الممكن ان نرجع له مرة اخرى ان شاء الله

لاهميته الكبيرة ..

---

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

بقي مجموعة واحدة فقط .. سنغطيها في الجزء الثالث ان شاء الله

الامثلة كلها بالمرفقات ..

glut tutrials.zip

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

مشكور اوى عزيزى الشمرى على الدروس . اسلوبك حلو ومبسط و بيجيب من الآخر. :D

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

شي طيب :)

---

الدرس الثاني عشر :

النوافذ الفرعية

Sub-windows

ماهي النوافذ الفرعية ؟

عندك نافذة تطبيقك ..

تستطيع ان تقسمها الى عدة اقسام ..

كل قسم له خصائص يختلف بها عن الاخر ..

مثلا :

تستطيع ان تجعل خصائص النافذة الفرعية ليست مثل النافذة الام .

الفائدة :

التحكم الكبير بتطبيقك .. كثيرا من الالعاب التي تشاهدها .. الالعاب العالمية .. والغير عالمية . .

ترى الشاشة تم تقسيمها مثلا الى قسمين ..

قسم للاعب الاول . وقسم للاعب الثاني ..

اللاعب الاول يغير طريقة العرض .. بعض الخصائص .. موقع الكميرا .. على راحته ..

ومع ذلك اللاعب الثاني لا يتأثر .. بتلك التعديلات ..

الفوائد اكثر من ان تعد او تحصى ..

الدالة :

int glutCreateSubWindow(int parentWindow, int x, int y, int width, int height);

الدالة السابقة تنشئ لنا نافذة فرعية ..

تطلب منا خمسة بارمترات ,

الاول قيمة النافذة الام .. يعني النافذة التي ستحتضن نافذتنا ..

كيف نأتي بهذه القيمة ..

تتذكر الدالة

glutCreateWindow("arab team - glut  ");

هذه تصنع النافذة الام .. النافذة الرئيسية ..

وتعيد قيمة من نوع int تمثل قيمة هذه النافذة .. يعني وسيلتنا للتخاطب مع هذه النافذة هي هذه القيمة

لاحظ

	int main_window = glutCreateWindow("arab team - glut  ");

اعلنت عن متغير .. وجعلت قيمته تساوي قيمة النافذة الرئيسية ..

الان نعود للنافذة الفرعية ونكتب

glutCreateSubWindow(main_window .....);

الامر واضح ..

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

البارمتر الرابع والخامس طول وعرض النافذة ..

لاحظ الصورة ..

04_09_05_12_05_07_1125817507sub.JPG

ان شاء الله الامر واضح ..

تنبيه !!!

بامكانك انشاء نافذة فرعية تنتمي لنافذة فرعية وهكذا دواليك ..

مثال

	int main_window = glutCreateWindow("arab team - glut  ");

  int sub_window = glutCreateSubWindow(main_window,200,200,200,200);


 int sub_window_2 = glutCreateSubWindow(sub_window,100,100,100,100);

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

مو بسيط ... لان الكود السابق لايكفي ..

نحتاج الى وجود دالة عرض لكل نافذة وهي

glutDisplayFunc(....);

اذا اردنا استخدام الماوس ..والتعرف على رسائله .. نحتاج لان نضع لكل نافذة الدالة التي تفعل الماوس والتعرف على رسائله ..

وغير لك ...

لكن انتبه .

الدالة glutIdleFunc تستدعيها مرة واحدة اذا اردت .. وهي الخاصة بالانيمشن ... راجع درسها ..

ستتوضح الكثير من الامور .. عند التطبيق .

سنضع التطبيق ..

سنجعل لكل نافذة .. دالة لتفسير رسائل الماوس والكيبورد الخاصة بها .. ودالة العرض الخاصة بها .

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


static int z=-5;

void reshape(int w, int h) {

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



}

void key(unsigned char c,int x, int y )
{
if(c == 'a'){
      z++;glutPostRedisplay(); }

if(c == 'b'){
  z--;

 glutPostRedisplay(); }


}




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

glLoadIdentity();
glTranslatef(0,0,z);

glutSolidCube(1);




 

 glutSwapBuffers();

}



void main(int argc, char **argv) {
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);
glutInitWindowPosition(100,100);
glutInitWindowSize(400,400);
int main_window = glutCreateWindow("arab team - glut  ");



 glClearColor(1,0,0,1);

  glutDisplayFunc(render);

    glutReshapeFunc(reshape);

 glutKeyboardFunc(key);


 int sub_window = glutCreateSubWindow(main_window,200,200,200,200);


  glClearColor(0,1,0,1); ////
    glutDisplayFunc(render );

 






glutMainLoop();
}

لاجديد ..

الا هنا

	int sub_window = glutCreateSubWindow(main_window,200,200,200,200);


  glClearColor(0,1,0,1); ////
    glutDisplayFunc(render );

قلنا نريد خلفية النافذة الفرعية خضراء

glClearColor(0,1,0,1); ////

وهي من دوال gl

وشيء مهم جدا ..

glutDisplayFunc(render );

لابد ان تضع للنافذة الفرعية دالة العرض الخاصة بها .. كما تلاحظ

glutDisplayFunc(render );

طبعا تستطيع ان تضع دالة render خاصة بها مثلا تسميها render_2 ..

وشيء اخر..

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

ستلاحظ .. انك اذا ضغطت a او b سيقترب او يبتعد منك الشكل المرسوم .. لكن لو كانت الماوس

فوق النافذة الخضراء الفرعية لن يحدث شيء .. لماذا ..

لان دالة رسائل الماوس خاصة بالنافذة الاصلية .. فقط .. كما هو الحال ايضا في القوائم -- menus--..

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

الخلاصة :

النوافذ الفرعية .. لايوجد لها الكثير من الدوال الخاصة .. لكن مشكلتها تحتاج الى فهم لما يجري .. ماذا تحتاج كل نافذة فرعية .. ماهي الدوال التي يجب ان تنفرد بها .. وماهي الدوال التي يمكن ن تشترك معها غيرها من النوافذ ..

الدرس الثالث عشر والاخير :

كيفية عمل رندر الى النوافذ الفرعية ..

سأَعرض مثال .. واعلق عليه .. اذا اتقنت هذا المثال .. فان شاء الله .. انت قادر على عمل لعبة .. مثلا سباق سيارات للاعبين :P

لايوجد اوامر جديدة .. الا امر واحد .... وهو

void glutSetWindow(int windowIdentifier);

هنا تختار النافذة .. التي تريد .. (القيمة العائدة من انشاء النافذة ) تستفيد من هذه الدالة في العديد من الامور مثلا .. لو اردت ان تعمل رندر لشكل ما .. في النافذة الفرعية .. الخ ..

سنقوم بعمل ثلاث دوال

render

تسوي لنا رندر للنافذة الرئيسية

لانريد ان نرسم شيء في النافذة الرئيسية ..فقط سنصبغها باللون الاسود ..

render_2

تعمل لنا رندر (تصيير ) لرسوماتنا في النافذة الفرعية الاولى ..

render_3

تعمل لنا رندر لنافذتنا الفرعية الثانية

نريد ان نعرف ثلاث متغيرات عامة ..

  int main_window,sub_window,sub_window_2;

وهي التي ستحتفظ بقيمة النوافذ ...

الان :

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


static int z=-5;

 int main_window,sub_window,sub_window_2;

void reshape(int w, int h) {

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



}



void key(unsigned char c,int x, int y )
{
if(c == 'a')
      z++;

if(c == 'b')
  z--;

 glutPostRedisplay();  


}




void render(void)
{
glutSetWindow(main_window);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 glutSwapBuffers();

}

void render_2()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glutSetWindow(sub_window );
glLoadIdentity();
glTranslatef(0,0,z);
glutSolidCube(1);
glutSwapBuffers();
}





void render_3()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glutSetWindow(sub_window_2);
glLoadIdentity();
glTranslatef(0,0,z);
glutSolidCube(1);
glutSwapBuffers();
}



void main(int argc, char **argv) {
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);
glutInitWindowPosition(100,100);
glutInitWindowSize(400,400);
  main_window = glutCreateWindow("arab team - glut  ");



 glClearColor(0,0,0,0);

  glutDisplayFunc(render);

    glutReshapeFunc(reshape);



   sub_window = glutCreateSubWindow(main_window,0 , 0,200,400);

    glutReshapeFunc(reshape);

  glClearColor(0,1,0,1);
 
  glutDisplayFunc(render_2 );

 glutKeyboardFunc(key);


  sub_window_2 = glutCreateSubWindow(main_window,200 , 0,200,400);



     glutReshapeFunc(reshape);
  glClearColor(0,0,1,1);
    glutDisplayFunc(render_3 );
 glutKeyboardFunc(key);




glutMainLoop();
}

لا يوجد شيء صعب .

   main_window = glutCreateWindow("arab team - glut  ");



 glClearColor(0,0,0,0);

  glutDisplayFunc(render);

    glutReshapeFunc(reshape);

هنا انشأنا النافذة الرئيسية ..

دالة العرض فيها هي render .. لنرى ماذا يوجد بها

 void render(void) 
{
glutSetWindow(main_window);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 glutSwapBuffers();

}

اذا لايوجد بها اي شيء ... فقط مسحنا البفر .. وقلبنا السطح .. ولاحظ اننا اخترنا النافذة الرئيسية ..

glutSetWindow(main_window);

للدلالة على ان النافذة التي تستخدم هذه الدالة .. هي الدالة الرئيسية ..

ملاحظة اخرى

 glClearColor(0,0,0,0);

لونا النافذة باللون الاسود ..

ننتقل الى النافذة الفرعية

   sub_window = glutCreateSubWindow(main_window,0 , 0,200,400);

    glutReshapeFunc(reshape);

  glClearColor(0,1,0,1);
 
  glutDisplayFunc(render_2 );

 glutKeyboardFunc(key);

لاحظ الاحداثيات والطول والعرض + لاحظ اللون الذي اخترناه + لاحظ دالة الكيبورد

glutKeyboardFunc(key);

يعني اننا نريد تفعيل دالة التعامل مع الكيبورد واخترنا الدالة التي انشأناها قبل قليل key

ولاحظ دالة العرض render_2

سننتقل اليها لنرى ماذا كتبنا بها

void render_2()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glutSetWindow(sub_window );
glLoadIdentity();
glTranslatef(0,0,z);
glutSolidCube(1);
glutSwapBuffers();
}

اخترنا النافذة الفرعية الاولي

glutSetWindow(sub_window );

ثم رسمن الشكل الذي نريده .

*** ملاحظة ***

عندما نحدد الشكل المرسوم ..

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

وليست الاصلية ..

--

النافذة الفرعية الثانية :

   sub_window_2 = glutCreateSubWindow(main_window,200 , 0,200,400);



     glutReshapeFunc(reshape);
  glClearColor(0,0,1,1);
    glutDisplayFunc(render_3 );
 glutKeyboardFunc(key);

نفس عمل النافذة السابقة الا اننا غيرنا الاحداثيات . و . دالة العرض . render_3

ماذا يوجد بدالة العرض .

void render_3()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glutSetWindow(sub_window_2);
glLoadIdentity();
glTranslatef(0,0,z);
glutSolidCube(1);
glutSwapBuffers();
}

اخترنا النافذة الفرعية الثانية .. ورسمنا

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

من خلال هذا التطبيق البسيط .. تلاحظ مدى السهولة الكبيرة .. والفائدة الكبيرة .

فنحن الان قادرون لى انشاء العاب ان شاء الله .. .. يمكن ان يعلب بها لاعبين او حتى عشر لاعبين لو اردنا : )

لكن لو استغنينا عن glut .. ممكن تجد صعوبة نوعا ما في تطبيق هذه المفاهيم ..

تنبيه اخير *

الى الان لم نغطي اهم جانب في النوافذ الفرعية .. وهو طرق العرض .. يعني ان نجعل لكل نافذة زاوية ؤية محددة ... reshape ....

لكن لايوجد دوال جديدة .. ولكن مفاهيم جديدة ..

والسبب في عدم تغطية هذا الموضوع .. انه خارج تماما عن نطاق glut .. وسنتعب في opengl .. وهذا ما لا نريده الان ..

الى هنا ننتهي من رحلتنا السريعة في مكتبة glut .. مع العلم اننا لم نغطي كل شيء ..

glut_13.zip

تم تعديل بواسطه الشمري
0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

جهد كبير , شكراً لك

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

السلام عليكم ..

و الله دروس رائعة ..

لم انتهي منها بعد (كالعادة) ..

و عندي كم سؤال بس راح أأجلهم الى ان انتهي ..

بس لدي الأن استفسار بسيط ..

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 .. ستعرف الفائدة من تلك الدوال بحول الله وقوته .. 

اخي العزيز ..

أين اجد شرح على هذه الدوال ..

يعني هل قمت انت بشرحها في احدى دروسك ..

انا بحثت و وجدت في احد الدروس

void ReShape(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();
}

لايهم فهمها الان .. سأشرحها لاحقا بحول الله وقوته .. . اقصد سأحاول شرحها لاني مش فاهمها 100% .

لا ادري هل قمت بشرحها ام لا ..

اذا قمت فأرجو ان تضع لي رابط الشرح ..

و اذا لا :( فراح ننتظر ..

و ايضا ..

تنبيه !

الدوال

glPushMatrix

glTranslatef

glRotatef

glPopMatrix

خاصة بopengl وبالتالي لا مجال لشرحها هنا .

الحمد لله ، وجدت شرحها الكامل في موضوع الازاحة والتدوير والتحجيم ..

جزاك الله كل خير ..

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

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

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

ولكن ليس كلاما موسعا .. ان شاء الله في موضوع قريب سافصل ان شاء الله ..

على العموم هي سهلة ..

ااما الباقي فكما ذكرت .. ستجده في موضوع الازاحة .

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

بارك الله فيك ..

سأبحث في الموضوع ..

اخي ممكن سؤال شخصي ؟؟

ممكن اعرف اسمك ..

اذا بتحب و ما عندك مانع لكي اناديك به ، ارجو ان لايزعجك طلبي :)

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
زوار
This topic is now closed to further replies.

  • يستعرض القسم حالياً   0 members

    لا يوجد أعضاء مسجلين يشاهدون هذه الصفحة .