الفريق العربي للبرمجةأرشيف المنتديات · 2000 – 2023
نسخة أرشيفية للقراءة فقط — التسجيل والمشاركة مغلقان، والمحتوى محفوظ كما كان.

مسائل منخفضة المستوى لا بد من الالمام بها!

مغلق
بدأه hasan_aljudy في 8 ديسمبر 2005 · 4 رد · 4,400 مشاهدة · في قسم برمجة الألعاب و الرسوميات العام
مشاركة: واتساب X فيسبوك تيليجرام
#1 صاحب الموضوع

أولا: الارقام بالـ binary و الـ hexadecimal و العلاقة بينهما

كما تعلمون (و بدون فلسفة زايدة) الكومبيوتر يتعامل مع الارقام على شكل اصفار و آحاد, 01000111 و يتبع في هذا نظاما للأرقام يختلف عن النظام اللذي نتبعه نحن البشر, فالرقم

10

بالنسبة لنا هو الرقم عشرة, لماذا؟ لانه مكون من خانتين, اول خانة هي خانة الاحاد, و قيمتها صفر, و ثاني خانة و هي خانة العشرات, و قيمتها واحد, اذا هناك صفر آحاد + واحد عشرات = صفر + عشرة = عشرة

بالنسبة للحاسوب, فالرقم

10

هو اثنان, لان النظام الثنائي يعتبر الخانة الأولى هي خانة الواحد, و الخانة الثانية هي خانة الاثنان, يمكن اعتبار ان 0 هو off او مغلق, و 1 هو on او مفتوح.

هنا خانة الواحد off, و خانة الاثنين هي on, يعني صفر + اثنان = اثنان.

ليس هذا المجال للاسهاب في شرح نظم الاعداد, لا بد من وجود العديد من المواضيع في هذا المنتدى او في اماكن مختلفة من الانترنت تتحدث عن هذا الموضوع.

ابسط طريقة لتحديد ما هي قيم رقم ثنائي, مثل

100101001

هي التفكير في ارقام الخانات على انها تحمل قيمة معينة, و لتحديد قيمة الرقم, نقوم باخذ جميع الخانات اللتي تحمل رقم 1, و نقوم باضافة قيم هذه الخانات الى بعضها.

في الارقام العشرية, فان الخانات مرتبة هكذا:

آحاد - عشرات - مئات - آلاف ... الخ

او, بنفس الطريقة, لو كتبناها على شكل ارقام:

واحد - عشرة - مئة - الف - عشرة الاف - مئة الف ... الخ

او

1 - 10 - 100 - 1000 - 10000 ... الخ

حيث كل خانة هي الخانة السابقة مضروية في عشرة, و ذلك لان النظام عشري!

في النظام الثنائي, فإن كل خانة هي الخانة السابقة مضروبة في 2:

1 - 2 - 4 - 8 - 16 - 32

مثلا, هذا الرقم:

100101001

يمكن تحليله هكذا:

    1       0         0        1         0         1         0          0           1
-----------------------------------------------------------------------
   256   125      64       32       16         8         4          2           1

لاخذ قيمة الرقم, ننظر الى الخانات اللتي تحمل رقم 1, و نجمع قيمها:

1 + 8 + 32 + 256 = 41 + 256 = 297

طيب,

كتابة الارقام و تذكرها على شكل ثنائي امر صعب و معقد بعض الشيء, لذلك معظم الناس يفضلون استخدام الظام الست عشري hexadecimal لكتابة الارقام الثنائية ..

النظام الست عشري, يبدا من 0 ..9 ثم يستخدم الحروف f .. a من اجل تمثيل الارقام من 10 الى 15

اما الخانات فهي تتضاعف بمقدار 16 في كل خانة

الجميل في هذا النظام, هي امكانية تحويل الارقام من النظام binary الى النظام hexadecimal مباشرة دون حسابات معقدة, و ذلك عن طريق اخذ كل 4 خانات (بتات) و تحويلها على حدة,

مثلا,

1100

هو الرقم 12, و بالـ hex هو C

اذا, 1100 تتحول الى C

و الرقم

0110

هو الرقم 6, و بالـ hex هو ايضا 6

اذا, يمكن تحويل الرقم

11000110

الى

C6

و ذلك لانه يمكن تحويل كل 4 خانات على حدة,

       11000110
        /         \
      /             \
    /                 \
1100              0110
   |                   |
   |                   |
   |                   |
   |                   |
  C                   6
     \               /
       \           /
         \       /
           \   / 
            C6

كل ما عليك معرفته, هو كيفية تحويل رقم ثنائي ذو اربع خانات الى رقم عشري (او ست عشري)

و هذا بسيط, فخانات الرقم الثنائي هي: 1 2 4 8

يعني, 1100 هي 12 لأن ثالث و رابع بت هما 8 و 4 و هما الوحيدان اللذان يحملان الرقم 1, لذلك نجمعهما للحصول على الرقم.

مثلا, الرقم الست عشري

F03C

هو:

1111000000111100

حيث:

   F          0        3           C
   |          |         |           |
   |          |         |           |
   |          |         |           |
1111     0000    0011      1100

ما دفعني لكتابة هذا الموضوع هو سؤال الاخ الشمري عن الـ bit patterns في موضوع سابق, و حينها اجبت اجابة مقتضبة نوعا ما, و كنت اقرأها قبل قليل و شعرت بأن اجابتي غير شافية, ففكرت في كتابة موضوع خاص عن الموضوع.

هناك مواضيع أخرى من هذا القبيل اود التحدث عنها إن شاء الله:

- عمليات الـ bit masking, و هي متعلقة بهذا الموضوع.

- حساب احداثيات الـ pixels على الشاشة, او التحويل بين index احادي الابعاد و index ثنائي الابعاد .. حيث ان الشاشة بالنسبة لنا مربعة, و كل بكسل له احداثيين, سيني و صادي, و لكن بالنسبة للحاسوب, الشاشة عبارة عن linear frame buffer, او سلسلة خطية من النقاط.

انا متأكد انه من يقرأ هذا الموضوع ستظل عنده اسئلة عالقة بدماغه, فيا ريت اللي عنده سؤال يسأل! (مللت من تكرار هذه الجملة دون فائدة).

يا جماعة لو حد معبر الموضوع ده من أصله خلي يسأل!!!

#2

اصبر يومين .. بس ..ورح تشوف اسئلتي على اصولها .... (مبتدئ)

لكن عندي تساؤلين ... باقي الاسئلة اخليها لموضوعك عن gldrawpixel ..

نفرض اني اريد رسم شيء شبيه بالشكل التالي .

111111111111

000000000000

111111111111

000000000000

كيف يمكن احول هذه الارقام الى شكل .. بحيث الرقم واحد نقطة ملونة ... الرقم صفر فراغ ..

ماذا يحدث خلف الكواليس ..

كيف تعمل دالة شبيهة بـ glDrawPixel

اقتباس
حساب احداثيات الـ pixels على الشاشة, او التحويل بين index احادي الابعاد و index ثنائي الابعاد .. حيث ان الشاشة بالنسبة لنا مربعة, و كل بكسل له احداثيين, سيني و صادي, و لكن بالنسبة للحاسوب, الشاشة عبارة عن linear frame buffer, او سلسلة خطية من النقاط
.

لم افهم ... معلومة جديدة .. ممكن توضح ..

---

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

اعتقد لقيت طرف الخيط ..... اوضح لك بعدين . :) ,,,,

تم تعديل هذه المشاركة بواسطة الشمري في 8 ديسمبر 2005 في 17:01

logo1.png تطبيق طمأنينة ، نسخة بيتا على أندرويد

عبدالله الشمّري - Al-Shammari

CodingAlone.com

twitter @abshammeri

abshammeri AT gmail.com

github : abshammeri

#3

سؤالك يدخلنا في الـ bit masking و هذه الشغلات .. التلاعب بالبتات ..

زين, نحتاج نعرف نتعامل مع الـ bitwise logical operations, يعني & و | و ^ و ~ و << و >>

قبل ان ندخل في الـ bitwise logic, ننظر للـ logic بشكل عام.

اذا قلت:

if( a && b )
{
    do something .....
}

فتقوم باختبار a و b, و اذا كان كليهما صحيح او true تقوم بتنفيذ العملية,

اما في حال استخدام

if( a || b )

فيكفي ان يكون واحد منهما true

true && true = true
true && false = false

true || false = true
true || true = true
false || false = false

زين, نفس الشي الـ bitwise logic, باستثناء انه بدل true و false نتعامل مع 0 و 1

يعني,

0 & 1 = 0
1 & 1 = 1

في الـ & (و هي bit-wise and) لازم يكون كلا المعاملين 1 لكي تحصل على 1, و الا حصلت على 0

في الـ | (و هي bitwise or) اذا كان اي واحد من المعاملين هو 1 فالناتج سيكون 1

1 | 1 = 1
1 | 0 = 1
0 | 0 = 0

اذا جبت رقمين عاديين و عملت عليهم & ما اللذي يحصل؟

مثلا, 12 & 20

اللذي يحصل هو تطبيق الـ bit-wise and على كل بت على حدة, و الناتج سيعتمد على شكل البتات ..

يعني:

12 = 01100
20 = 10100

12 & 20 =
01100 & 10100

which is:

0 1 1 0 0
1 0 1 0 0   & 
------------
0 0 1 0 0 

00100 = 4

so, 
12 & 20 = 4

لنجرب 12 | 20:

12 | 20 =
01100 | 10100

which is:

0 1 1 0 0
1 0 1 0 0   |
------------
1 1 1 0 0

11100 = 28

so, 
12 | 20 = 28

طيب, بقيت شغلة اخرى: ~ او complement و هي في الحقيقة not او عكس الشي ..

~0 = 1
~ 1 = 0

و لو طبقتها على رقم, فستطبقها على كل بت على حدة:

مثلا,

~12 = ~1100 = 0011 = 3

و لكن الناتج يعتمد على كم بت تستخدم لتخزين الرقم؟ هنا استخدمها اربعة بتات .. و لكن لو استخدمنا 16 بت مثلا:

~12 = ~0000000000001100 = 1111111111110011 = something ...

نستطيع استخدام هذه الأشياء من أجل التلاعب بالبتات بطريقة لا تخطر على البال! (بالحقيقة هي بسيطة)

مثلا, لو لدينا رقم مكون من ثمان بتات كلها اصفار

00000000

و نريد ان نخلي قيمة البت الخامس = 1, كيف؟

بسيطة, نعمل له and هكذا:

//to convert 00000000 to 00010000:

byte x = 0;
x = x | 32;

/*
x = x | 32:

x = 00000000
32 = 00010000

x | 32 is:

00000000
00010000 |
-------------
00010000

*/

يمكن تطبيق هذه الفكرة لتغيير البت الخامس الى 1 في أي رقم .. يعني لو عندنا

11000011

و نريد نغير البت الخامس الى 1, نقوم بعمل or مع 32

11000011
00010000 |
--------------
11010011

الفكرة هي اختيار رقم معين بحيث ان البت الخامس فيه هو 1 و كل باقي البتات هي 0

هذا الرقم هو 32 (و هو الرقم الوحيد)

و يمكن بنفس المنطق معرفة الرقم الموجود في أي بت ... عن طريق عمل and,

مثلا, الرقم 36 (في 8 بتات), نريد نعرف, هل البت السادس هو 1 ام 0؟

نختار رقم بحيث تكون كل بتاته اصفار ما عدا البت السادس هو 1, يعني

00100000

و هذا الرقم هو 164, و نعمل له and مع الرقم المطلوب اختباره:

36 & 164

36   = 00010100
164 = 00100000

36 & 164 =

00010100
00100000 &
------------
00000000 

so:
36 & 164 = 0

طيب, حصلنا النتيجة من الـ and, كيف نستخدم هذه النتيجة لمعرف هل البت السادس 1 ام صفر؟

بسيطة, اذا كان الناتج 0, فمعناها انه عملية الـ and على كل البتات انتجت اصفارا, بما ان كل البتات في 164 هي اصفار ما عدا الرقم السادس, فهذا يعني ان البت السادس في الرقم 36 لم يكن1, لانه لو كان واحد لما كانت نتيجة الـ and هي صفر

القصد, لو كان الناتج صفر, فهذا يعني ان البت السادس صفر, و لو كان النائتج اي شي آخر (ليس صفر) فهذا يعني ان البت السادس هو 1

نفس الشي مع كل البتات,

طيب, انا قلت انك تختار رقم بحيث كل البتات 0 ما عدا البت المراد اختباره ..

هناك طريق للحصول على هذا الرقم دون تفكير! عن طريق الـ shifting, عن طريق الاشارات: << و >>

مثال:

x << 3

تعني اعمل ازاحة للبتات في x بمقدار ثلاث بتات الى اليسار

مثلا, لو كانت x هي

000001100

فإن x << 3 هي:

001100000

حيث قمنا بتحريك البتات في الرقم بمقدار ثلاث خطوات الى اليسار

و من هذا نستنتج أن:

1 << x

تعني خذ الرقم

00000001

و اعمل له ازاحة الى اليسار بمقدار x

!!!

يعني لو كانت x هي خمسة, فالنتيجة ستكون:

1 << 5 is:

00000001 << 5

= 

00010000

ألا تلاحظون شيئا؟

نستطيع بهذه الطريق الحصول على رقم معين, بحيث تكون كل بتاته 0 ما عدا البت السابع مثلا .. هذا الرقم هو:

1 << 7

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

طيب, المثال:

لنفرض ان لدينا رقم معين, و نريد ان نقوم بكتابة هذا الرقم على شكل binary

سنقوم بقرائة كل بت على حدة (بالتسلسل), و اذا كان هذا البت هو 1 نقوم بكتابة 1, اما اذا كان صفر سنقوم بكتابة 0,

تذكروا انه في البنتيوم فإن الارقام تمثل في الذاكرة باستخدام 32 بت,

الكود بالسي بلص بلص:

#include <iostream>
using namespace std;

int main()
{
    int number = 2345;

    for( int i = 0; i < 32; i++ )
    {
        int currentBit = number & (1 << i);
        if( currentBit != 0 )
        {
            cout << 1;
        }
        else
        {
            cout << 0;
        }
    }

    cout << endl;


    return 0;
}

الناتج من تشغيل البرنامج:

10010100100100000000000000000000
Press any key to continue . . .

الفكرة هي عمل loop و المرور على جميع البتات و معرفة قيمها.

اذا استوعبتم هذا المثال ممكن نحاول نطبق الفكرة من اجل رسم خط منقط عن طريق تحديد الـ pattern في البتات

تم تعديل هذه المشاركة بواسطة hasan_aljudy في 10 ديسمبر 2005 في 05:05

#4

أعتقد بدأت افهم ..

الامثلة ... افضل .

شوف هذا

#include <glut.h>
#include <stdlib.h>


GLubyte rasters[24] = {
0xc0, 0x00, 0xc0, 0x00, 0xc0, 0x00, 0xc0, 0x00, 0xc0, 0x00,
0xff, 0x00, 0xff, 0x00, 0xc0, 0x00, 0xc0, 0x00, 0xc0, 0x00,
0xff, 0xc0, 0xff, 0xc0};
void init(void)
{
glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
glClearColor (0.0, 0.0, 0.0, 0.0);
}
void display(void)
{
glClear(GL_COLOR_BUFFER_BIT);
glColor3f (1.0, 1.0, 1.0);
glRasterPos2i (20, 20);
glBitmap (10, 12, 0.0, 0.0, 11.0, 0.0, rasters);
glFlush();
}
void reshape(int w, int h)
{
glViewport(0, 0, (GLsizei) w, (GLsizei) h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho (0, w, 0, h, -1.0, 1.0);
glMatrixMode(GL_MODELVIEW);
}
void keyboard(unsigned char key, int x, int y)
{
switch (key) {
case 27:
exit(0);
}
}
int main(int argc, char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
glutInitWindowSize(100, 100);
glutInitWindowPosition(100, 100);
glutCreateWindow(argv[0]);
init();
glutReshapeFunc(reshape);
glutKeyboardFunc(keyboard);
glutDisplayFunc(display);
glutMainLoop();
return 0;
}

يطبع حرف f ...

كل الكود المطلوب

GLubyte rasters[24] = {
0xc0, 0x00, 0xc0, 0x00, 0xc0, 0x00, 0xc0, 0x00, 0xc0, 0x00,
0xff, 0x00, 0xff, 0x00, 0xc0, 0x00, 0xc0, 0x00, 0xc0, 0x00,
0xff, 0xc0, 0xff, 0xc0};
void init(void)
{
glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
glClearColor (0.0, 0.0, 0.0, 0.0);
}
void display(void)
{
glClear(GL_COLOR_BUFFER_BIT);
glColor3f (1.0, 1.0, 1.0);
glRasterPos2i (20, 20);
glBitmap (10, 12, 0.0, 0.0, 11.0, 0.0, rasters);
glFlush();
}

ماذا تعني البيانات التي بالمصفوفة ..

لو لاحظت ..

يوجد ثلاث ارقام عشرية فقط

0xc0

0xff

0x00

طبعا انا مو قاعد اشرح .. انا قاعد احاول بس .

0x00

تساوي

00000000

صح ...

و

0xff

تساوي

11111111

اما

0xc0

تساوي

11000000

العدد الاول يمثل الللون الاسود .. OFF

الثاني اللون الابيض >> ON

الثالث .. ايضا لون ابيض

حرف F هو هكذا ,

11111111111
1111
11111111111
1111
1111
1111
1111

فنحن نحتاج الى رقم " بت " اصفار و واحد ..

الصفر يمثل فراغ .

واحد يمثل بيكسل ملون .

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

بالتالي اذا كتبت

0xff

هنا سأرسم خط .. مكون من ثمانية بكسلات ..

11111111

ثم مرة اخرى

0xff

11111111

ثم اريد عدد ثنائي بهذه الصيغة

11100000

فمثلا لو اردنا تمثيل حرف مثل E

1111111111000000
1111111111000000
1100000000000000
1100000000000000
1111111111000000
1111111111000000
1100000000000000
1100000000000000
1111111111000000
1111111111000000

بالمصفوفة /

نبدا من اسفل الحرف الى اعلاه .

GLubyte rasters[20] = {
0xff, 0xc0, 0xff, 0xc0, 
0xc0, 0x00, 0xc0, 0x00,
0xff, 0xc0, 0xff, 0xc0, 
0xc0, 0x00, 0xc0, 0x00,
0xff, 0xc0, 0xff, 0xc0, 
};

هذه مجرد محاولة ... وجربتها وطلعت صحيحة .

مثلا ::: هل يوجد من يحاول طباعة حرف مثل Y

0000100000001000
0000010000010000
0000001000100000
0000000101000000
0000000010000000
0000000010000000
0000000010000000

ياليت نشوف تجارب ..

وايضا تفصيل اكثر حول بارمترات الدالة glBitmap ...

ومشكور يا حسن على هذا الموضوع .

logo1.png تطبيق طمأنينة ، نسخة بيتا على أندرويد

عبدالله الشمّري - Al-Shammari

CodingAlone.com

twitter @abshammeri

abshammeri AT gmail.com

github : abshammeri

#5

ممتاز .. B)

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

محاولة لحرف y بس بايخة :lol:

/*
0000110000000110 //0c 06
0000011000000110 //06 06 
0000001100001100 //03 0c
0000000110001100 //01 8c
0000000011011000 //00 d8
0000000000110000 //00 30
0000000001100000 //00 60
0000000110000000 //01 80
0000011000000000 //06 00
0001100000000000 //18 00
*/

 GLubyte yRaster[] =
 {
     0x18, 0x00,
     0x06, 0x00,
     0x01, 0x80,
     0x00, 0x60,
     0x00, 0x30,
     0x00, 0xd8,
     0x01, 0x8c,
     0x03, 0x0c,
     0x06, 0x06,
     0x0c, 0x06,
 };

في شغلة غريبة في الـ glBitmap ..

اول شي هذي صفحة msdn اللتي تتكلم عنها:

http://msdn.microsoft.com/library/default....func01_1a5s.asp

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

جربت الان مع حرف y فحصلت تغيرات شنيعة!

عموما يمكن نناقش هذا في موضوع آخر,

بصراحة هسة ما بيه حيل اكتب او افكر كثير .. :lol:

هذا الموضوع مغلق.

مواضيع مشابهة