یک دوره در برنامهنویسی و گرافیک کامپیوتری با Visual C++
چکیده
این مقاله یک درس گرافیک کامپیوتری برای دانشجویان سالهای پایانی و دانشجویان تحصیلات تکمیلی مهندسی مکانیک و هوافضا در دانشگاه بوفالو را شرح میدهد. این درس علاوه بر نظریهٔ گرافیک سهبعدی، بر برنامهنویسی برای گرافیک کامپیوتری نیز تمرکز دارد و در محیط رایانههای شخصی و ویندوز مایکروسافت با استفاده از Visual C++ تدریس میشود.
مقاله مروری کوتاه بر تاریخچهٔ این درس و ارتباط آن با دیگر درسهای طراحی به کمک رایانه ارائه میکند. راهبرد معرفی برنامهنویسی با VC++ شامل تمرینهای اولیهٔ شیءگرا بدون گرافیک، سپس روشهای برنامهنویسی برای عملیات پایهٔ گرافیک دوبعدی در ویندوز است. پس از آن، پیادهسازی برنامهنویسی گرافیک سهبعدی با قالب شیءگرا و در نهایت روش معرفی OpenGL برای رایانههای شخصی دنبال میشود.
مقدمه
ما سالهاست در دانشگاه بوفالو درسی دربارهٔ گرافیک کامپیوتری برای دانشجویان سالهای پایانی و دانشجویان تحصیلات تکمیلی مهندسی مکانیک و هوافضا ارائه میکنیم. این درس یکی از مجموعهدرسهای ما در زمینهٔ طراحی به کمک رایانه و گرافیک کامپیوتری است. از دیگر درسهای این مجموعه میتوان به درس طراحی مکانیکی با استفاده از AutoCad و ProEngineer اشاره کرد که اخیراً برای دانشجویان BSME به درس الزامی تبدیل شده است؛ همچنین درس دوم ProEngineer که به عناصر محدود، مکانیزمها و ساخت میپردازد، و یک درس برنامهنویسی گرافیک واقعیت مجازی مبتنی بر برنامهنویسی ایستگاههای کاری و شامل World Tool Kit. در حالت معمول، درس مورد بحث پیشنیاز درس واقعیت مجازی است.
کار آموزشی ما در حوزهٔ برنامهنویسی گرافیک کامپیوتری از روزگار برنامهنویسی Fortran و پایانههای کامپیوتری «green screen» شرکت Tektronix، یعنی بسیار پیش از رواج بستههای CAD، آغاز شد. این درس مقدماتی برنامهنویسی گرافیک کامپیوتری در طول زمان و با حضور مدرسان، سختافزارها و محیطهای نرمافزاری گوناگون، از جمله UNIX و DOS، تکامل یافته است. در سالهای اخیر تعهد خود را به برنامهنویسی ویندوز روی رایانههای شخصی با استفاده از Visual C++ تثبیت کردهایم.
محیط برنامهنویسی VC++ بسیار رضایتبخش بوده است. دانشجویانی که پیشزمینهٔ بسیار اندکی در علوم کامپیوتر دارند، میتوانند خود را با برنامهنویسی شیءگرای C++ و Application Wizard در VC++ سازگار کنند. آنها میتوانند در آزمایشگاههای رایانهٔ گروه برنامهنویسی کنند، کار خود را بهسادگی با رایانهٔ شخصی به خانه ببرند و برنامههایی تولید کنند که شباهت زیادی به برنامههای تجاری مورد استفادهٔ روزمرهٔ آنها دارد. در نقاط مختلف این درس، واکنش مشترکی مانند «پس روش انجام کار همین است» شنیده میشود. این درس مهارتهای مشخص برنامهنویسی و نظری در گرافیک کامپیوتری ایجاد میکند که به هر محیط محاسباتی دیگری نیز قابل انتقال هستند. در عین حال، آشنا کردن دانشجویان با برنامهنویسی ویندوز روی رایانهٔ شخصی، مهارتهای محاسباتی آنان را بهطور محسوسی گسترش میدهد.
این مقاله ماهیت درس گرافیک کامپیوتری و موضوعات مختلفی را که در آن پوشش داده میشوند خلاصه میکند و همچنین میکوشد دیدی نسبت به برنامهنویسی Visual C++ و شیوهٔ ادغام آن با یک درس گرافیک کامپیوتری ارائه دهد.
فرضها و مبانی
این درس بهصورت مشترک در مقطع کارشناسی با شمارهٔ MAE 473 و در مقطع تحصیلات تکمیلی با شمارهٔ MAE 573 و تحت عنوان «گرافیک کامپیوتری برای CAD» ارائه میشود. بهجز موارد خاص، پیشزمینهٔ برنامهنویسی دانشجویان کارشناسی و تحصیلات تکمیلی تقریباً یکسان است. معمولاً آنها در سال اول یا دوم با برنامهنویسی C آشنا شدهاند، اما مدتی است که برنامهنویسی زیادی انجام ندادهاند. بنابراین مرور برنامهنویسی C را همزمان با معرفی محیط Visual C++ آغاز میکنیم.
از Application Wizard در VC++ برای برنامهنویسی ویندوز استفاده میشود تا دانشجویان بتوانند بدون درگیر شدن با تمام جزئیات ریز ویندوز، برنامهنویسی کنند. بااینحال، در ابتدا از قالب «Console Application» در VC++ استفاده میکنیم. در این قالب، وقتی برنامهٔ کامپایل و لینکشده اجرا میشود، پنجرهای شبیه DOS با نمایش الفبایی و بدون قابلیت گرافیکی تولید میکند. برنامهنویسی در این حالت بسیار ساده است؛ میتوان آن را در یک فایل واحد داخل محیط توسعهٔ یکپارچهٔ VC++ انجام داد. کد بهراحتی ویرایش، کامپایل و لینک میشود و اجرای برنامه نیز در حین توسعه بدون خروج از محیط بهسادگی انجام میگیرد.
قالب Console Application برای شروع کار با Visual C++ بسیار مناسب است. این قالب فرصتی برای مرور آرایهها و اشارهگرها، که معمولاً دانشجویان در آنها نیاز به تمرین بیشتری دارند، و نیز بحث دربارهٔ برنامهنویسی شیءگرا، که دانشجویان غالباً درک مبهمی از آن دارند، فراهم میکند. کتاب معروف Horton در Visual C++ نیز از همین شیوه آغاز میشود. روشهای دیگری مانند رویکرد Gurewich و Gurewich که بدون ایجاد نخستین این مفاهیم، خیلی سریع وارد برنامهنویسی ویندوز میشوند، برای کاربردهای مهندسی کمتر مناسباند.
دو برنامهٔ نمونهٔ ما که از اشیا استفاده میکنند در شکلهای ۱ و ۲ آمدهاند و در مقالهٔ شکلها قرار گرفتهاند. اینها پنجرههای DOS مربوط به قالب Console Application هستند. برنامهٔ نخست خروجیهای یک «کلاس مستطیل» و یک «کلاس دایره» را با استفاده از تابعهای عضو مناسب نشان میدهد. در برنامهٔ شکل ۲، کلاسهای مستطیل و دایره از یک کلاس TwoDobjects مشتق شدهاند. از تابعهای مجازی استفاده شده است تا بتوان آرایهای از TwoDobjects شامل هر دو نوع مستطیل و دایره را بهآسانی مدیریت کرد. تابعهای عضوی که برای مستطیل یا دایره طراحی شدهاند، در صورت نیاز برای اشیای مشخص بهصورت خودکار فراخوانی میشوند.
مفاهیم برنامهنویسی ویندوز
دنیای برنامهنویسی ویندوز، البته، بهشدت به روششناسی شیءگرا وابسته است؛ نه فقط برای برنامهنویسی، بلکه برای سازماندهی پایهٔ برنامه نیز. نوشتن برنامه برای ویندوز جزئیات فوقالعاده زیادی دارد که بخش اعظم آنها بهوسیلهٔ تابعها و سازماندهی تعبیهشده در کامپایلر و سیستمعامل فراهم میشوند. مانند بسیاری از محصولات مایکروسافت، تقریباً همهچیز در VC++ در دسترس است؛ اما این فراوانی ابزارها بهحدی است که پیدا کردن مستقیمترین و کاربردیترین ابزارها برای یک برنامه میتواند دشوار باشد. در این درس، تلاش کردهایم روی ابزارهایی تمرکز کنیم که برای گرافیک و محاسبات مهندسی پایهتر هستند. وقتی دانشجویان این ابزارهای پایه و محیط VC++ را یاد بگیرند، میتوانند نسبتاً آسان به قابلیتهای دیگر VC++ منتقل شوند.
ما برای برنامههای ویندوز خود از قالب اجرایی AppWizard در VC++، شامل معماری Document/View، استفاده کردهایم. در این قالب، VC++ ساختار یک برنامه/پروژه را ایجاد میکند که بهعنوان الگو برای برنامهٔ برنامهنویس عمل میکند. اگر فرایند ششمرحلهای راهاندازی AppWizard را با پذیرش همهٔ مقادیر پیشفرض دنبال کنید، خود AppWizard بیستوپنج فایل کد C++ ایجاد میکند. بدون افزودن هیچ کدی، پروژهٔ حاصل را میتوان کامپایل و لینک کرد و فایلهای دیگری، از جمله فایل اجرایی، تولید خواهند شد. هنگام اجرا، یک پنجرهٔ معمولی اما خالی روی صفحه ایجاد میشود که در آن هیچ اتفاقی رخ نمیدهد. اساساً تمام کد ازپیشنوشتهٔ VC++ برای نمایش این پنجرهٔ خالی و فراهم کردن منابع لازم جهت آغاز برنامهنویسی کاربردی استفاده میشود. از بسیاری جهات، این شیوه برنامهنویسی ویندوز را شبیه نوشتن بخشی از برنامهٔ شخص دیگری میکند، نه نوشتن برنامهٔ خودتان. البته هنوز کار بسیار زیادی باقی میماند، اما این کار نیازمند درک محیط و چگونگی کار کردن درون آن است.
معماری Document/View در AppWizard سازمانی برای برنامه فراهم میکند که در آن دادهها بخشی از یک «سند» در نظر گرفته میشوند. بخش اعظم برنامهنویسی در دو کلاس C++ انجام میشود. یک کلاس، کلاس Document، برای ذخیره و دستکاری دادههای سند است و کلاس دیگر، کلاس View، برای نمایش بصری دادههای سند و مدیریت تعاملات با کاربر برنامه است. هر دو کلاس Document و View از کلاسهای سطح بالاتر مشتق شدهاند و از طریق کتابخانههای Visual C++ و Microsoft Foundation Classes یا MFC به تابعها، کلاسها و منابع کاربردی فراوانی دسترسی دارند. این مجموعه شامل قابلیتهای گرافیکی OpenGL و DirectX مایکروسافت نیز هست که هر دو تعامل نرمافزار/سختافزار را از طریق کارتهای گرافیکی پیشرفته تسهیل میکنند.
آغاز برنامهنویسی ویندوز
کلاس View در یک پروژه شامل تابعهایی است که برای قرار دادن اطلاعات روی صفحه و تعامل با کاربر طراحی شدهاند. تابع OnDraw از کلاس View توسط سیستمعامل ویندوز هنگام آغاز اجرای برنامه و همچنین هر زمان که نیاز به بهروزرسانی یا ترسیم مجدد پنجرهٔ برنامه باشد فراخوانی میشود. شکل ۳ پنجرهٔ نخستین برنامهٔ ویندوزی ما با نام FirstWin را نشان میدهد. این پنجره هم گرافیک و هم متن دارد که بهوسیلهٔ تابع OnDraw زیر ترسیم شدهاند.
OnDraw تابع عضو کلاس View است. در برنامهٔ FirstWin، نام مشخص کلاس View بهطور خودکار توسط AppWizard در VC++ به CFirstWinView داده شده است؛ پیشوند C صرفاً به معنای «class» است. تابع OnDraw نیز در قالبی آماده توسط AppWizard ایجاد شده بود و در ابتدا شامل خطوط ۰۱ تا ۰۵ و خط ۱۷ زیر بود. خط ۰۵ محل افزودن کد توسط برنامهنویس را مشخص میکند. ما خطوط ۰۶ تا ۱۶ را اضافه کردهایم و اینها تنها خطوط کدی هستند که در سراسر برنامهٔ FirstWin افزوده شدهاند.
در این کد، خط ۰۱ نشان میدهد که اشارهگر pDC هنگام فراخوانی OnDraw توسط سیستمعامل ویندوز به تابع منتقل میشود. این اشارهگر دستگاه زمینه، یعنی پنجرهٔ جاری، را که OnDraw باید در آن ترسیم کند مشخص میکند. خط ۰۸ از اشارهگر pDC برای فعال کردن تابع TextOut استفاده میکند و عبارت This is a Box and a Dot! را از فاصلهٔ ۲۵ پیکسل از بالای پنجره و ۵۰ پیکسل از لبهٔ چپ قرار میدهد. خط ۰۷ یک شیء CString با نام Buffer را تعریف میکند و خط ۰۹ Buffer را به شکلی قالببندی میکند که متن و دو متغیر صحیح تعیینکنندهٔ مرکز کادر را در خود داشته باشد. خط ۱۰ دوباره از pDC برای تعیین پنجره استفاده کرده و Buffer را درست زیر عبارت مربوط به کادر و نقطه مینویسد. خط ۱۱ پیکسل واقع در مرکز کادر را تعیین میکند و خطوط ۱۲ تا ۱۶ خود کادر را ترسیم میکنند.
01 void CFirstWinView::OnDraw(CDC* pDC)
02 {
03 CFirstWinDoc* pDoc = GetDocument();
04 ASSERT_VALID(pDoc);
05 // TODO: add draw code for native data here
06 int CenterX = 300, CenterY =50;
07 CString Buffer;
08 pDC->TextOut(50,25,"This is a Box and a Dot!");
09 Buffer.Format("The Dot is at %d, %d",CenterX, CenterY);
10 pDC->TextOut(50,50,Buffer);
11 pDC->SetPixel(CenterX,CenterY,0);
12 pDC->MoveTo(CenterX - 25, CenterY - 25);
13 pDC->LineTo (CenterX + 25, CenterY - 25);
14 pDC->LineTo (CenterX + 25, CenterY + 25);
15 pDC->LineTo (CenterX - 25, CenterY + 25);
16 pDC->LineTo (CenterX - 25, CenterY - 25);
17 }
تابع OnDraw بالا پنجرهٔ شکل ۳ را بهخوبی ترسیم میکند، اما کار دیگری انجام نمیدهد. برای تعامل با کاربر، پیامهای ویندوز، که مثلاً در نتیجهٔ فشردن یک کلید یا کلیک ماوس ایجاد میشوند، باید پردازش شوند یا تابعهای فرمانی برای پاسخ به کلیک روی منوها یا نوارهای ابزار توسعه داده شوند. تابعهای مناسب را میتوان از طریق ClassWizard در VC++ ایجاد کرد و در صورت نیاز بهصورت خودکار در کلاس View یا Document قرار داد.
تابع زیر نمونهای از یک کنترلکنندهٔ پیام ماوس در برنامهٔ سادهٔ ترسیم SimpleDraw است. کلاس View در اینجا CSimpleDrawView نام دارد و این تابع، با نام OnLButtonDown، هر زمان که دکمهٔ چپ ماوس در پنجرهٔ SimpleDraw فشرده شود اجرا میشود. خطوط ۰۱ تا ۰۳ و خط ۱۴ توسط VC++ هنگام ایجاد تابع فراهم شدهاند و خطوط ۰۴ تا ۱۳ شامل کدی هستند که اضافه شده است.
01 void CSimpleDrawView::OnLButtonDown(UINT nFlags, CPoint point)
02 {
03 // TODO: Add your message handler code here and/or call default
04 CSimpleDrawDoc* pDoc = GetDocument();
05 CClientDC aDC(this);
06 aDC.SelectObject(&m_BluePen);
07 int i = pDoc->NumLines;
08 aDC.MoveTo(pDoc->FPoint[i]);
09 aDC.LineTo(point);
10 pDoc->LPoint[i] = point;
11 pDoc->FPoint[i+1] = point;
12 pDoc->NumLines++;
13 CView::OnLButtonDown(nFlags, point);
14 }
خط ۰۴ یک اشارهگر pDoc به «سندی» که برای ذخیرهٔ دادههای ترسیم در حال ساخت استفاده میشود به دست میدهد. خط ۰۵ زمینهٔ دستگاه سمت مشتری را با نام aDC به پنجرهٔ جاری مرتبط میکند. خط ۰۶ یک قلم آبی را برای ترسیم انتخاب میکند. خط ۰۷ با استفاده از اشارهگر سند، تعداد فعلی خطوط ترسیم را بهدست میآورد. خط ۰۸ به نخستین نقطهٔ خط جاری، که قبلاً در سند ذخیره شده است، حرکت میکند. خط ۰۹ خطی تا نقطهای که کاربر روی آن کلیک کرده رسم میکند. متغیر point در زمان کلیک ماوس، موقعیت مکاننما را دریافت میکند؛ همانطور که در فهرست آرگومانهای خط ۰۱ دیده میشود. سپس خطوط ۱۰ و ۱۱ نقطهٔ جدید را هم بهعنوان آخرین نقطهٔ خط جاری و هم بهعنوان نخستین نقطهٔ خط بعدی در سند ذخیره میکنند. در نهایت خط ۱۲ شمارندهٔ خطوط را افزایش میدهد. در این آرایش، تابع OnDraw برنامهٔ SimpleDraw بهگونهای کدنویسی شده است که وقتی ویندوز در اثر تغییر اندازه، کمینهکردن یا تنظیم پنجره آن را فراخوانی میکند، تمام مجموعهٔ خطوط را از نخستین تا آخرین خط دوباره ترسیم کند.
شکل ۴ نمونهای از برنامهٔ ترسیم با ماوس است که گسترش یافته تا توسعهٔ موارد تخصصی نوار منو و نوار ابزار را نشان دهد. بستهٔ منابع VC++ امکان تعریف سادهٔ هر یک از این موارد و اتصال آنها به تابعهایی را فراهم میکند که با کلیک فعال میشوند. در این برنامه، کلیک روی موارد منو و فهرستهای بازشونده تابعهایی را فعال میکند که میتوانند مقادیر پارامترها را برای تنظیم رنگ خط، ضخامت خط و مانند آن تغییر دهند. موارد نوار ابزار نیز معمولاً بهگونهای تعریف میشوند که میانبر همان موارد منوی بازشونده باشند.
ادامهٔ بحث دربارهٔ برنامههای ویندوز، گرافیک سهبعدی، OpenGL و جمعبندی در مقالههای بعدی این مجموعه آمده است.