الدرس السابق
OpenGL .. الدرس رقم 4
تعريف بالدرس ..
نتعلم في هذا الدرس الإكساء .. بماذا يفيدنا الإكساء ؟ .. تخيل بانك تريد عمل قذيفة لتتحرك أمامك على الشاشة .. لو أردنا عمل القذيفة بالتقنيات التي درسناها سابقا أي بالمضلعات فسوف نحصل على قذيفة .. ولكن لن
عليها بشكل احترافي .. فسوف تكون القذيفة عبارة عن مجموعة من المربعات والمثلثات تغطيها بعض الألوان وتطير في عرض الشاشة .. هل هذا مانريده حقا ؟ بالطبع لا وهنا نحتاج الى الإكساء .. تخيل بأنه لدينا صورة حقيقة لقذيفة او صورة مصممة بالفوتوشوب أو الماكس لقذيفة .. نستطيع اضافتها إلى قذيفتنا التي قمنا بتصميمها حتى تعطينا شكل خارجي حقيقي للقذيفة هذا من جهة .. من جهة أخرى الإكساء يساعد على جعل التطبيق يعمل بسرعة .. فالقذيفة اذا كانت بدون اكساء تكون عبارة عن المئات من المضلعات بينما بالاكساء تكون عبارة عن قطعة واحدة وهي الصورة التي قمنا باستخدامها لإكساء القذيفة .. في درسنا هذا سوف نقوم باستخدام الاكساء على مربع .. بسم الله نبدأ
الدرس ..
#include <windows.h>
#include <stdio.h>
#include <gl\gl.h>
#include <gl\glu.h>
#include <gl\glaux.h>
HDC hDC=NULL;
HGLRC hRC=NULL;
HWND hWnd=NULL;
HINSTANCE hInstance;
bool keys[256];
bool active=TRUE;
bool fullscreen=TRUE;
GLfloat xrot;
GLfloat yrot;
GLfloat zrot;
GLuint texture[1];
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
الكود السابق موجود في الدرس الاول بإستثناء 5 اضافات جديدة عليه
الإضافة الاولى هي الملف الرأسي #include <stdio.h> وهذا الملف الرأسي يجعلنا نتعامل مع الملفات حيث نحتاج لاحقا الأمر fopen() والذي لايعمل بدون هذا الملف الرأسي
الإضافة الثانية والثالثه والرابعة هي GLfloat لكل من X , Y , Z وهو يقوم بتدوير المربع حول تلك المحاور
الإضافة الأخيرة هي السطر قبل الأخير وفي صرحنا اننا سوف نستخدم الاكساء والذي هو عبارة عن صورة واحدة فقط واذا اردنا اضافة اكثر من صورة نقوم بكتابة العدد بدل الرقم 1
AUX_RGBImageRec *LoadBMP(char *Filename)
{
FILE *File=NULL;
الآن سوف نقوم بوضع الكود الذي يقوم بتحميل الصورة التي سنستخدمها للإكساء .. الصورة التي سنختارها يجب ان يكون كل من العرض width والارتفاع height على الاقل 64 بكسل وكحد أقصى 256 بكسل .. يوجد طرق اخرى لتجاوز تلك الارقام ولكن لم اعرفها حتى الآن .
في الكود السابق قمنا بإنشاء الهاندل handle والهاندل عبارة عن قيمة تستخدم لتعريف المصادر المراد استخدامها في البرنامج حتى يتعرف عليها البرنامج ويقوم باستخدامها والوصول اليها
if (!Filename)
{
return NULL;
}
الكود السابق يقوم بفحص ما اذا كان الملف الذي ترغب بتحميله قد تم تحديده ام لا
File=fopen(Filename,"r");
اذا تم تحديده يقوم الكود السابق بفحص الملف فإذا كان موجودا يقوم بفتحه
if (File)
{
fclose(File);
return auxDIBImageLoad(Filename);
}
اذا كان الملف الذي أردنا فتحه مفتوح أساسا سوف يقوم الكود السابق باغلاقه
return NULL;
}
اذا لم نستطع فتح الملف سوف يقوم البرنامج بالخروج
int LoadGLTextures()
{
الكود السابق يقوم بتحميل الصورة وتحويلها حتى يتم استخدامها للإكساء
int Status=FALSE;
الكود السابق يقوم بتعريف متغير الحالة Status وتم وضع False لانه لم يتم تحميل الصورة حتى الآن
AUX_RGBImageRec *TextureImage[1];
الكود السابق يستخدم لتخزين معلومات الصورة المراد استخدامها مثل العرض والارتفاع
memset(TextureImage,0,sizeof(void *)*1);
الكود السابق يقوم بعمل مسح clear لاي معلومات قد تكون موجودة لصورة قد تكون محفوظة سابقا
if (TextureImage[0]=LoadBMP("Data/NeHe.bmp"))
{
Status=TRUE;
الكود السابق يقوم بتحميل الصورة التي سوف تستخدم للإكساء وهي Nehe.bmp وعند اكتمال العملية بصورة صحيحة سوف يتم حفظ معلومات الصورة من خلال المتغير TextureImage[0]
glGenTextures(1, &texture[0]);
glBindTexture(GL_TEXTURE_2D, texture[0]);
الآن بعد ان قمنا بتخزين بيانات الصورة في TextureImage[0] سوف نقوم باستخدام تلك البيانات لتكوين الصورة على المربع
من الكود السابق
السطر الأول
glGenTextures(1, &texture[0]) يخبر البرنامج باننا نريد استخدام صورة واحدة فقط للإكساء وتذكر اننا في بداية البرنامج أيضا قد صرحنا بهذا الشيء ف GLuint texture[1] الموجودة في اول البرنامج تخبر البرنامج باننا نريد استخدام صورة واحدة فقط للإكساء
السطر الثاني من الكود السابق يقوم بالربط بين المعلومات التي تم تخزينها عن الصورة وبين الصورة نفسها ومن ثم تهيئتها لوضعها على المربع
glTexImage2D(GL_TEXTURE_2D, 0, 3, TextureImage[0]->sizeX, TextureImage[0]->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[0]->data);
GL_TEXTURE_2D يقوم باخبار البرامج باننا نستخدم مادة اكساء ثنائية الأبعاد
TextureImage[0]->sizeX يعبر عن عرض الصورة المراد استخدامها للإكساء
TextureImage[0]->sizey يعبر عن ارتفاع الصورة المراد استخدامها للإكساء
TextureImage[0]->data هو المكان الذي يأخذ منه البرنامج بيانات الصورة
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
}
الكود السابق يقوم برؤية ما اذا كانت الصورة أكبر أو اصغر من الحجم المطلوب على الشاشة ومن ثم تعديلها
if (TextureImage[0])
{
if (TextureImage[0]->data)
{
free(TextureImage[0]->data);
}
free(TextureImage[0]);
}
الكود السابق يقوم بتحرير الذاكرة المستخدمة في حفظ بيانات الصورة بعد التأكد من حفظ البيانات
return Status;
}
اذا تم كل ماسبق فان الكود السابق يجعل البرنامج يستمر واذا وجد خطأ فان البرنامج يقوم بالخروج
int DrawGLScene(GLvoid) // Here's Where We Do All The Drawing
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear Screen And Depth Buffer
glLoadIdentity(); // Reset The Current Matrix
glTranslatef(0.0f,0.0f,-5.0f);
glRotatef(xrot,1.0f,0.0f,0.0f); // Rotate On The X Axis
glRotatef(yrot,0.0f,1.0f,0.0f); // Rotate On The Y Axis
glRotatef(zrot,0.0f,0.0f,1.0f); // Rotate On The Z Axis
glBindTexture(GL_TEXTURE_2D, texture[0]); // Select Our Texture
glBegin(GL_QUADS);
// Front Face
glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f); // Bottom Left Of The Texture and Quad
glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 1.0f); // Bottom Right Of The Texture and Quad
glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, 1.0f); // Top Right Of The Texture and Quad
glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, 1.0f); // Top Left Of The Texture and Quad
// Back Face
glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f); // Bottom Right Of The Texture and Quad
glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f); // Top Right Of The Texture and Quad
glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, 1.0f, -1.0f); // Top Left Of The Texture and Quad
glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, -1.0f); // Bottom Left Of The Texture and Quad
// Top Face
glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f); // Top Left Of The Texture and Quad
glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, 1.0f, 1.0f); // Bottom Left Of The Texture and Quad
glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, 1.0f, 1.0f); // Bottom Right Of The Texture and Quad
glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, -1.0f); // Top Right Of The Texture and Quad
// Bottom Face
glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, -1.0f, -1.0f); // Top Right Of The Texture and Quad
glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, -1.0f, -1.0f); // Top Left Of The Texture and Quad
glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 1.0f); // Bottom Left Of The Texture and Quad
glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f); // Bottom Right Of The Texture and Quad
// Right face
glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, -1.0f, -1.0f); // Bottom Right Of The Texture and Quad
glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, -1.0f); // Top Right Of The Texture and Quad
glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, 1.0f, 1.0f); // Top Left Of The Texture and Quad
glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 1.0f); // Bottom Left Of The Texture and Quad
// Left Face
glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f); // Bottom Left Of The Texture and Quad
glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f); // Bottom Right Of The Texture and Quad
glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, 1.0f, 1.0f); // Top Right Of The Texture and Quad
glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f); // Top Left Of The Texture and Quad
glEnd();
الكود السابق لرسم وتحريك المربع وتم شرحه في دروس سابقة
الكود المصدري للدرس
الدرس الأصلي لمن أراد الإطلاع
انتهى الدرس
أسألكم الدعاء
علي الدعيج