用Direct2D和DWM来做简单的动画效果
2016-03-19 19:36
381 查看
0.由来
画流程图的时候需要根据数据画出每帧流场图制作出“动画”,而在Win7以上平台,Direct2D和IUAnimation结合可以做出很流畅的动画来。1.一个简单例子
先看看效果这个例子是根据MS官方的一个Win32例子改在MFC对话框下实现的。这里基本没有用到IUAnimation类,而是用了DWM。下面贴代码
2.流程
a.初始化D2D相关类,初始化DWM对象b.构造D2D绘图对象
c.画图
d.按照DWM返回值刷新绘图对象的位置
3.部分代码
//根据start end duration计算实时位置,共4种方法-线性匀速,指数 template <class T> class Animation { public: Animation(T start, T end, T duration) : m_Start(start), m_End(end), m_Duration(duration) { } void SetStart(T start) { m_Start = start; } T GetStart() { return m_Start; } void SetEnd(T end) { m_End = end; } T GetEnd() { return m_End; } void SetDuration(T duration) { m_Duration = max(0, duration); } T GetDuration() { return m_Duration; } T GetValue(T time) { time = min(max(time, 0), m_Duration); return ComputeValue(time); } protected: virtual T ComputeValue(T time) = 0; T m_Duration; T m_Start; T m_End; }; template <class T> class LinearAnimation : public Animation<T> { public: LinearAnimation(T start=0, T end=0, T duration=0) : Animation(start, end, duration) { } protected: virtual T ComputeValue(T time) { return m_Start + ((m_End - m_Start) * (time / m_Duration)); } }; template <class T> class EaseInExponentialAnimation : public Animation<T> { public: EaseInExponentialAnimation(T start=0, T end=0, T duration=0) : Animation(start, end, duration) { } protected: T ComputeValue(T time) { return m_Start + (m_End - m_Start) * pow(2, 10 * (time/m_Duration - 1)); } }; template <class T> class EaseOutExponentialAnimation : public Animation<T> { public: EaseOutExponentialAnimation(T start=0, T end=0, T duration=0) : Animation(start, end, duration) { } protected: T ComputeValue(T time) { return m_Start + (m_End - m_Start) * (-pow(2, -10 * time/m_Duration) + 1); } }; template <class T> class EaseInOutExponentialAnimation : public Animation<T> { public: EaseInOutExponentialAnimation(T start=0, T end=0, T duration=0) : Animation(start, end, duration) { } protected: T ComputeValue(T time) { //compute the current time relative to the midpoint time = time / (m_Duration / 2); //if we haven't reached the midpoint, we want to do the ease-in portion if (time < 1) { return m_Start + (m_End - m_Start)/2 * pow(2, 10 * (time - 1)); } //otherwise, do the ease-out portion return m_Start + (m_End - m_Start)/2 * (-pow(2, -10 * --time) + 2); } }; template<class Interface> inline void SafeRelease(Interface **ppInterfaceToRelease) { if (*ppInterfaceToRelease != NULL) { (*ppInterfaceToRelease)->Release(); (*ppInterfaceToRelease) = NULL; } }
//d2d操作类 class CD2D { public: CD2D(); ~CD2D(); HRESULT CreateResources(HWND hWnd); HRESULT CreateDeviceResources(void); HRESULT Init(void); HRESULT OnRender(void); private: HWND m_hwnd; CRect rc; ID2D1Factory *m_pD2DFactory; ID2D1HwndRenderTarget *m_pRT; ID2D1PathGeometry *m_pPathGeometry; ID2D1PathGeometry *m_pObjectGeometry; ID2D1SolidColorBrush *m_pRedBrush; ID2D1SolidColorBrush *m_pYellowBrush; LinearAnimation<float> m_Animation;//线性 DWM_TIMING_INFO m_DwmTimingInfo; };
CD2D::CD2D() : m_hwnd(NULL), m_pD2DFactory(NULL), m_pRT(NULL), m_pPathGeometry(NULL), m_pObjectGeometry(NULL), m_pRedBrush(NULL), m_pYellowBrush(NULL), m_Animation() { } CD2D::~CD2D() { SafeRelease(&m_pD2DFactory); SafeRelease(&m_pRT); SafeRelease(&m_pPathGeometry); SafeRelease(&m_pObjectGeometry); SafeRelease(&m_pRedBrush); SafeRelease(&m_pYellowBrush); } HRESULT CD2D::CreateResources(HWND hWnd) { HRESULT hr; ID2D1GeometrySink *pSink = NULL; // Create a Direct2D factory. hr = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &m_pD2DFactory); D2D1_PIXEL_FORMAT pixelFormat = D2D1::PixelFormat( DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_IGNORE ); D2D1_RENDER_TARGET_PROPERTIES props = D2D1::RenderTargetProperties(); props.pixelFormat = pixelFormat; props.dpiX = 96.0f; props.dpiY = 96.0f; GetClientRect(hWnd, &rc); // Create a Direct2D render target hr = m_pD2DFactory->CreateHwndRenderTarget( props, D2D1::HwndRenderTargetProperties( hWnd, D2D1::SizeU(rc.right - rc.left, rc.bottom - rc.top) ), &m_pRT ); if (SUCCEEDED(hr)) { // Create the path geometry. hr = m_pD2DFactory->CreatePathGeometry(&m_pPathGeometry); } if (SUCCEEDED(hr)) { // Write to the path geometry using the geometry sink. We are going to create a // spiral hr = m_pPathGeometry->Open(&pSink); } if (SUCCEEDED(hr)) { D2D1_POINT_2F currentLocation = { 0, 0 }; pSink->BeginFigure(currentLocation, D2D1_FIGURE_BEGIN_FILLED); D2D1_POINT_2F locDelta = { 2, 2 }; float radius = 3; for (UINT i = 0; i < 30; ++i) { currentLocation.x += radius * locDelta.x; currentLocation.y += radius * locDelta.y; pSink->AddArc( D2D1::ArcSegment( currentLocation, D2D1::SizeF(2 * radius, 2 * radius), // radiusx/y 0.0f, // rotation angle D2D1_SWEEP_DIRECTION_CLOCKWISE, D2D1_ARC_SIZE_SMALL ) ); locDelta = D2D1::Point2F(-locDelta.y, locDelta.x); radius += 3; } pSink->EndFigure(D2D1_FIGURE_END_OPEN); hr = pSink->Close(); } if (SUCCEEDED(hr)) { // Create the path geometry. hr = m_pD2DFactory->CreatePathGeometry(&m_pObjectGeometry); } if (SUCCEEDED(hr)) { // Write to the object geometry using the geometry sink. // We are going to create a simple triangle hr = m_pObjectGeometry->Open(&pSink); } if (SUCCEEDED(hr)) { pSink->BeginFigure( D2D1::Point2F(0.0f, 0.0f), D2D1_FIGURE_BEGIN_FILLED ); const D2D1_POINT_2F ptTriangle[] = { { -10.0f, -10.0f },{ -10.0f, 10.0f },{ 0.0f, 0.0f } }; pSink->AddLines(ptTriangle, 3); pSink->EndFigure(D2D1_FIGURE_END_OPEN); hr = pSink->Close(); } SafeRelease(&pSink); return hr; } HRESULT CD2D::CreateDeviceResources(void) { HRESULT hr = S_OK; if (m_pRT != nullptr) { if (SUCCEEDED(hr)) { // Create a red brush. hr = m_pRT->CreateSolidColorBrush( D2D1::ColorF(D2D1::ColorF::Red), &m_pRedBrush ); } if (SUCCEEDED(hr)) { // Create a yellow brush. hr = m_pRT->CreateSolidColorBrush( D2D1::ColorF(D2D1::ColorF::Yellow), &m_pYellowBrush ); } } return hr; } HRESULT CD2D::Init(void) { HRESULT hr; float length = 0; hr = m_pPathGeometry->ComputeLength( NULL, //no transform &length ); if (SUCCEEDED(hr)) { m_Animation.SetStart(0); //start at beginning of path m_Animation.SetEnd(length); //length at end of path m_Animation.SetDuration(5.0f); //seconds ZeroMemory(&m_DwmTimingInfo, sizeof(m_DwmTimingInfo)); m_DwmTimingInfo.cbSize = sizeof(m_DwmTimingInfo); // Get the composition refresh rate. If the DWM isn't running, // get the refresh rate from GDI -- probably going to be 60Hz if (FAILED(DwmGetCompositionTimingInfo(NULL, &m_DwmTimingInfo))) { HDC hdc = GetDC(m_hwnd); m_DwmTimingInfo.rateCompose.uiDenominator = 1; m_DwmTimingInfo.rateCompose.uiNumerator = GetDeviceCaps(hdc, VREFRESH); ReleaseDC(m_hwnd, hdc); } } return hr; } HRESULT CD2D::OnRender(void) { HRESULT hr; if (!(m_pRT->CheckWindowState() & D2D1_WINDOW_STATE_OCCLUDED))//是否堵塞 { D2D1_POINT_2F point; D2D1_POINT_2F tangent; D2D1_MATRIX_3X2_F triangleMatrix; D2D1_SIZE_F rtSize = m_pRT->GetSize(); float minWidthHeightScale = min(rtSize.width, rtSize.height) / 512; D2D1::Matrix3x2F scale = D2D1::Matrix3x2F::Scale( minWidthHeightScale, minWidthHeightScale ); D2D1::Matrix3x2F translation = D2D1::Matrix3x2F::Translation( rtSize.width / 2, rtSize.height / 2 ); // Prepare to draw. m_pRT->BeginDraw(); // Reset to identity transform m_pRT->SetTransform(D2D1::Matrix3x2F::Identity()); //clear the render target contents m_pRT->Clear(D2D1::ColorF(D2D1::ColorF::Black)); //center the path m_pRT->SetTransform(scale * translation); //draw the path in red m_pRT->DrawGeometry(m_pPathGeometry, m_pRedBrush); static float float_time = 0.0f; float length = m_Animation.GetValue(float_time); // Ask the geometry to give us the point that corresponds with the // length at the current time. hr = m_pPathGeometry->ComputePointAtLength(length, NULL, &point, &tangent); ASSERT(SUCCEEDED(hr)); // Reorient the triangle so that it follows the // direction of the path. triangleMatrix = D2D1::Matrix3x2F( tangent.x, tangent.y, -tangent.y, tangent.x, point.x, point.y ); m_pRT->SetTransform(triangleMatrix * scale * translation); // Draw the yellow triangle. m_pRT->FillGeometry(m_pObjectGeometry, m_pYellowBrush); // Commit the drawing operations. hr = m_pRT->EndDraw(); if (hr == D2DERR_RECREATE_TARGET) { hr = S_OK; } // When we reach the end of the animation, loop back to the beginning. if (float_time >= m_Animation.GetDuration()) { float_time = 0.0f; } else { float_time += static_cast<float>(m_DwmTimingInfo.rateCompose.uiDenominator) / static_cast<float>(m_DwmTimingInfo.rateCompose.uiNumerator); } } return hr; }
对话框界面中,删除所有按钮和static文本框,声明d2d变量m_d2d,在
OnInitDialog()里初始化
HRESULT hr; hr = m_d2d.CreateResources(GetSafeHwnd()); if (SUCCEEDED(hr)) { hr = m_d2d.CreateDeviceResources(); if (SUCCEEDED(hr)) { hr = m_d2d.Init(); } }
在
OnPaint()里
m_d2d.OnRender(); // CDialogEx::OnPaint();一定要注释掉,会自己刷新
相关文章推荐
- Gifski:一个跨平台的高质量 GIF 编码器
- 模仿动画的放大缩小容器
- jQuery 1.9.1源码分析系列(十五)动画处理之缓动动画核心Tween
- Android实现定制返回按钮动画效果的方法
- Android中ViewFlipper的使用及设置动画效果实例详解
- jQuery实现美观的多级动画效果菜单代码
- php判断GIF图片是否为动画的方法
- jQuery实现动画效果circle实例
- HTML5游戏引擎LTweenLite实现的超帅动画效果(附demo源码下载)
- 浅析JavaScript动画
- js排序动画模拟-插入排序
- javascript+HTML5的Canvas实现Lab单车动画效果
- 基于javascript实现漂亮的页面过渡动画效果附源码下载
- js实现按钮颜色渐变动画效果
- 超赞的jQuery图片滑块动画特效代码汇总
- jQuery实现连续动画效果实例分析
- jQuery实现的给图片点赞+1动画效果(附在线演示及demo源码下载)
- jQuery实现带有洗牌效果的动画分页实例
- jQuery动画效果相关方法实例分析
- jquery实现先淡出再折叠收起的动画效果