PDA

View Full Version : پويانمايي (Animation)



AAAAAS
چهارشنبه 07 بهمن 1388, 21:26 عصر
سلام

من مشكلي در ساخت پويانمايي يا Animation دارم كه وقتي برنامه را اجرا ميكنم تصوير داراي پرش (Flickering) است. مشكل اين است كه من ميخواهم چند مستطيل را بصورت متحرك نشان بدهم اما چون مستطيلها يكي يكي رسم مي شوند دچار پرش ميشود اگر
اين مستطيلها بصورت يك تصوير و به طور فريم فريم نمايش داده شود ديگر داراي پرش نيست.

لطفا اگر توابعي در اين مورد هست كه يك مستطيل يا هر شكل ديگر را تبديل به تصوير كند
و فريم فريم نشان دهد يا راههاي بهتر ديگري اگر هست برايم كاملا توضيح دهيد.

با تشكر.

Nima_NF
چهارشنبه 07 بهمن 1388, 22:44 عصر
اگر قرار هست که خودتان مستطیل ها را رسم کنید باید به شکل زیر عمل کنید تا flicker نداشته باشید:

شما در هر فراخوانی WM_Paint/OnDraw یا هر جای دیگر که رسم می کنید، باید یک بافر bitmap به اندازه کل تصویر بسازید، سپس مستطیل ها را در آن رسم کنید و در آخر همه تصویر که به اندازه client area هست را نمایش دهید.
به عبارت دیگر تک تک مستطیل ها را رسم نمی کنید، بلکه همه را در یک بافر عکس رسم می کنید و سپس عکس را نمایش می دهید.

تا جایی که یادم هست روش فوق به double buffer مرسوم هست.

AAAAAS
چهارشنبه 07 بهمن 1388, 23:48 عصر
سلام:

بله درست است. double buffer را در كتاب خوانده ام اما مي خواهم توابع مورد نياز و طريقه ي استفاده از آنها را برايم بنويسيد.

با تشكر.

Nima_NF
پنج شنبه 08 بهمن 1388, 00:25 صبح
قطعه کد زیر با win32 هست، برای MFC نیز توابع معادل با همین نام ها وجود دارد.

- در برنامه WM_ERASEBKGND را 1 قرار دادیم تا برنامه خودش پس زمینه رسم نکند.
- با CreateCompatibleDC و CreateCompatibleBitmap حافظه مورد نظر برای عکس را می گیریم.
- سپس با Rectangle یک مستطیل در این حافظه رسم می کنیم.
- در پایان نیز با BitBlt کل عکس را از حافظه به تصویر کپی می کنیم و نمایش می دهیم تا flicker نداشته باشیم.
- اگر انیمیشن هست، تایمر بسازید و هر دفعه WM_PAINT را فراخوانی کنید و مکان مستطیل ها را تغییر دهید.





case WM_ERASEBKGND:
return (LRESULT)1;

// ----------------------------------------------------------------

case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);

//------------------- Method one (Without flickers)-----------------------------
HDC hdcMem;
HBITMAP hbmMem, hbmOld;
HBRUSH hbrBkGnd;

// Get the size of the client rectangle.
GetClientRect(hWnd, &rc);

// Create a compatible DC.
hdcMem = CreateCompatibleDC(hdc);

// Create a bitmap big enough for our client rectangle.
hbmMem = CreateCompatibleBitmap(hdc, rc.right-rc.left,
rc.bottom-rc.top);
// Select the bitmap into the off-screen DC.
hbmOld = (HBITMAP)SelectObject(hdcMem, hbmMem);

// Erase the background.
hbrBkGnd = CreateSolidBrush(GetSysColor(COLOR_WINDOW));
FillRect(hdcMem, &rc, hbrBkGnd);
DeleteObject(hbrBkGnd);

// Render the image into the offscreen DC.
SetBkMode(hdcMem, TRANSPARENT);
SetTextColor(hdcMem, GetSysColor(COLOR_WINDOWTEXT));
DrawText(hdcMem, TEXT("HELLO"), -1, &rc, DT_CENTER);

// Draw Rectangle into the offscreen DC.
hbr1 = CreateSolidBrush (RGB(0,0 ,155));
hbr2 = (HBRUSH) SelectObject (hdcMem, hbr1);
Rectangle (hdcMem, 100, 100, 300, 300);

// Blt the changes to the screen DC.
BitBlt(hdc, rc.left, rc.top, rc.right-rc.left, rc.bottom-rc.top,
hdcMem, 0, 0, SRCCOPY);


SelectObject (hdc, hbr2);
// Done with off-screen bitmap and DC.
SelectObject(hdcMem, hbmOld);

DeleteObject ( hbr1 );
DeleteObject(hbmMem);
DeleteDC(hdcMem);

//-------------------------------------------------------

// TODO: Add any drawing code here...
EndPaint(hWnd, &ps);

break;


چون سال ها قبل روی این موضوع کار کرده بودم، توانستم لینک آن را در سایت مایکروسافت پیدا کنم. اسم روش Off-Screen DC بود.
لینک برنامه فوق در سایت مایکروسافت (http://msdn.microsoft.com/en-us/library/ms969905.aspx)