مثال على استخدام glDrawPixels مع الشرح كود في الداخل

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

في OpenGL, نستطيع استخدام الـ function

glDrawPixels

من اجل رسم سلسلة من الـ pixels على شكل صورة (بمعنى آخر, من اجل رسم الصور).

ياخذ طول و عرض المربع (مربع الصورة), و ياخذ ايضا مكونات هذه الصورة على شكل سلسلة "خطية" متواصلة من الـ pixels او النقاط المكونة للصورة.

شكل الـ function يبدو هكذا:

void glDrawPixels( GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels
);

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

هناك عدة طرق لتمثيل pixel, احداها مثلا عن طريق اعطاء بايت واحد byte لكل pixel, و في هذه الحالة فإن قيمة هذا البايت تحدد index في الـ pallete يستخدم لتحديد لون هذا الـ pixel. و هذا يسمى indexed color

يمكن ايضا اعطاء byte واحد لكل مكون من مكونات اللون RGB او Red, Green, Blue, و قيمة كل بايت من 0 الى 255 تحدد مقدار هذا العنصر في اللون, مثلا 0,0,0 أسود, حيث لا يوجد اي لون.
255,0,0 يعني اقصى درجات الحمرة.
و هكذا. و هذا يسمى RGB, و على هذه الفرضية فإن كل لون يحتوي على 3 bytes او 24 bits, و لكن في الحقيقة معظم بطاقات العرض لا تحب التعامل مع 24 بت و تفضل التعامل مع 32 بت .. فهنالك byte إضافي, احيانا يستخدم من اجل لا شيء سوى سد الفراغ, و احيانا يستخدم من اجل تحديد شفافية اللون, او alpha. و بهذه الحالة يسمى RGBA حيث نستخدم 4 بايتات لكل بكسل, و بهذا الترتيب (كما هو واضح من الاسم).

      R         G            B             A
|--------|--------|--------|--------|


البارامتر format يستخدام لتحديد هذه الأشياء, و هو enum ياخذ عدة احتمالات, موجودة في صفحة الـ msdn في الرابط اعلى الموضوع.
سنستخدم GL_RGBA في هذه المثال.

السؤال الان هو كيف نمثل هذه البايتات في الـ array؟ هل نستخدم int لكل بكسل (و الـ int ياخذ 4 بايتات)؟ ام نستخدم 4 متغيرات من نوع byte لكل بكسل؟
اذا استخدمنا الـ int فسيكون علينا ان ننتبه فيما اذا كان النظام اللذي نعمل عليه هو big-endian او little-endian لان ترتيب البايتات سيختلف حسب النظام. لذلك من الأفضل استخدام سلسلة من الـ bytes.
لذلك سنختار للبارامتر الرابع, و هو type و هو ايضا enum, نختار منه GL_UNSIGNED_BYTE.
لماذا unsigned؟ اترك الاجابة لكم :P

بقيت مسألة واحدة و هي تحديد مكان الصورة!
لمن لا يعرف, opengl يعتبر بمثابة state machine, يعني انت تضعها في حالة معينة ثم ترسل لها اوامر, و استجابتها للاوامر تعتمد على الحالة اللتي وضعتها فيها.
لتحديد مكان الصورة, تقوم باستدعاء glRasterPos2d و تحدد الاحداثيات x,y اللتي تريد رسم الصورة فيها, و بعد ذلك تقوم باستدعاء glDrawPixels

المثال يستخدم glut, و من لا يعرفه يمكن مراجعة درس CompuM4n
http://www.arabteam2...showtopic=41970

#include<GL/glut.h> 

GLubyte * getPicture( int w, int h )
{
    int length = w * h * 4;
    GLubyte * bytes = new GLubyte[length];
    for( int i = 0; i < length; i++ )
    {
        bytes[i] = 0;
    }
    int m = min(w,h);

    //draw a line!
    for( int i = 0; i < m; i++ )
    {
        int p = i*4;
        p = p+p*w;
        int pe = p + 4;
        while( p <= pe )
        {
            bytes[p] = 200;
            p++;
        }        
    }

    return bytes;
}

void putMyImage( int x, int y, int w, int h )
{
    glRasterPos2d( x, y );
    glDrawPixels( w, h, GL_RGBA, GL_UNSIGNED_BYTE, getPicture( w, h ) );
}

void myInit()
{
    glClearColor(0.3,0.3,0.3,0.0);
    glColor3f(1.0,1.0,0.5);
    glPointSize(2.0);
    glMatrixMode(GL_PROJECTION);
    gluOrtho2D(0.0,640.0,0.0,480.0);
}

void display()
{
    glClear(GL_COLOR_BUFFER_BIT);
    glEnd();
    putMyImage( 100, 100, 20, 20 );
    glFlush();
   
}

int main(int argc, char** argv)
{
    glutInit(&argc,argv);
    glutInitDisplayMode(GLUT_SINGLE |GLUT_RGB);
    glutInitWindowSize(400,400);
    glutInitWindowPosition(50,50);
    glutCreateWindow("Draw Polygon");
    myInit();
    glutDisplayFunc(display);
    glutMainLoop();
    return 0;
}



هذا مثال glut تقليدي, و الكود اصلا لسست انا من كتبه, بل اخذته من مصدر من الانترنت و احتفظت بها, و بصراحة لم اعد اذكر ما هو المصدر!!!

الشي اللي اضفته هنا هو putMyImage حيث يتم استدعائه في display

void putMyImage( int x, int y, int w, int h )
{
       glRasterPos2d( x, y );
       glDrawPixels( w, h, GL_RGBA, GL_UNSIGNED_BYTE, getPicture( w, h ) );
}

البارامترات في glDrawPixels هي كما وضحت في السابق, و آخر بارامتر هو استدعاء لـ getPicture و هي تعطينا مصفوفة من الـ unsigned byte تمثل بكسلات الصورة.

الصورة عبارة عن خط, كونتها في getPicture بطريقة ساسوكية! حيث اقوم أولا بتلوين الصورة كلها بالأسود, ثم اعمل حلقية صغيرة اقوم من خلالها برسم الخط.
تفاصيل كيف كونت الصورة نفسها غير مهمة, و هي ليست لب الموضوع, بالامكان تكوين صورة بأي طريقة, و لكن المهم هو اننا عندنا array of pixels و قمنا برسمه على الشاشة,


اعرف ان الشرح ناقص, و قد فعلت هذا عمدا, حيث كتبت الموضوع على عجالة و من دون تحضير.
لماذا؟
حتى اللي عنده سؤال يسأل!

لعل و عسى بهذه الطريقة نحصل على بعض التفاعل!!!

لو كان هناك اي شيء في الشرح لم تفهمه, اسأل ولا تتردد, و لا تقلي الشرح واضح! لانه لا يبدو واضحا بالنسبة لي!