码迷,mamicode.com
首页 > 其他好文 > 详细

风火轮 – 动画效果

时间:2015-03-03 18:44:07      阅读:161      评论:0      收藏:0      [点我收藏+]

标签:opencv   风火轮   

风火轮越来越有广告范,之前实现的素材导入功能已能解决50%的用户需求,即可以拖入现成的动画、视频及图片素材,效果见QQ空间之前的某篇日志。

从进化发展角度来看,现在的很多产品,纯硬件的竞争已是薄利见血,软件功能提升才是王道。

所以,软件实现得加强。电子黑板如此,风火轮也如此。

准备实现动画效果。

闭门造车是白手起家的最脑残做法,所以先放眼成熟产品,看哪些功能与UI可以借鉴。

做素材,一般会选取FLASH、Photoshop,而动画效果,PPT是大家耳熟能详的。

仔细研究一下,决定采用PPT的界面,再参考PhotoShop的gif功能。

一、Ribbon界面

首先做PPT的动画界面,这个用Ribbon风格控件,就是花点时间的事,没太大的技术含量。

技术分享

最花时间的是找图标,不过现在别的不好找,代码、图标却是大把。

技术分享

花了半天时间,虽谈不上是神似,也能算得上是形似的了。具体功能将逐个实现。

 

二、动画基类

再看下PPT中的动画属性,其界面最终所围绕的也就是这两个

技术分享      技术分享

分解一下,设计几个数据结构:

         typedefstruct tagEnhanceInfo { // 增强选项

 

                   UnicodeStringSoundFileName; // 声音文件

                   TEffect_Enhance_AfterPlayAfterPlayMode; // 动画播放后处理方式

                   TColorAfterAnimationColor; // 变换为某种颜色,FAfterPlayMode为teapToColor有效

                   UnicodeStringAnimationText; // 动画文本

                   intDelayPercent; // 字母之间延迟百分比

         }ENHANCE_INFO;

 

         typedefstruct tagTimerInfo { // 计时选项

 

                   TEffect_Time_StartStartMode; // 开始选项

                   intDelay; // 延迟秒数

                   TEffect_Time_PeriodPeriodMode; // 期间选项

                   TEffect_Time_RepeatRepeatMode; // 重复选项

                   boolQuickBackAfterPlay; // 播完后快退

         }TIMER_INFO;

 

enum TEffect_Enhance_AfterPlay { // 增强选项-动画后播放选项

         teapToColor,// 变换为某种颜色

                   teapNoDarking,// 不变暗

                   teapHide,// 隐藏

                   teapHideAfterClick// 下次单击后隐藏

         };

 

enum TEffect_Time_Start { // 计时选项-开始选项

         ttsClick,// 单击时

                   ttsSameTimeAsPrevOne,// 与上一动画同时

                   ttsAfterPrevOne// 上一动画完成之后

         };

 

enum TEffect_Time_Period { // 计时选项-期间

         ttpVerySlow,// 非常慢

                   ttpSlow,// 慢速

                   ttpNormal,// 中速

                   ttpFast,// 快速

                   ttpVeryFast// 非常快

         };

 

enum TEffect_Time_Repeat { // 计时选项-重复

         ttrNone,// 无

                   ttr2,// 2

                   ttr3,// 3

                   ttr4,// 4

                   ttr5,// 5

                   ttr10,// 10

                   ttrTillNextClick,// 直到下一次单击

                   ttrTillEnd// 直到结束

         };

 

enum CbwEffectType { // 效果类型枚举量

         cetBase= 0, // TCbwAnimationEffect

                   cetAppear= 1, // TCbwAnimationEffect_Appear

                   cetFadeOut= 2, // TCbwAnimationEffect_FadeOut

                   cetFlyIn= 3, // TCbwAnimationEffect_FlyIn

                   cetEnd

};

 

enum CbwEffectDirection { // 动画方向

         cedFromBottom= 0, // 自底部

                   cedFromLeftBottom= 1, // 自左下部

                   cedFromLeft= 2, // 自左侧

                   cedFromLeftTop= 3, // 自左上部

                   cedFromTop= 4, // 自顶部

                   cedFromRightTop= 5, // 自右上部

                   cedFromRight= 6, // 自右侧

                   cedFromRightBottom= 7 // 自右下部

         };

为了更好地模块化,把对象相关的动画属性提取出来

 

         typedefstruct tagObjectMat {

                   TPointLeftTopPosition;

                   TCbwObject* Object;

 

                   cv::MatMat;

                   cv::MatMask;

 

                   void__fastcall BuildMask(int height, int width);

         }OBJECTMAT;

这样,可以设计动画基类为:

/**

 *@class TCbwAnimationEffect

 *@brief 动画基类

 *

 * 处理动画基本内容

 *@author 陈斌文

 *@version 1.0

 *@date 2015-03-03

 *@QQ: 282397369

 */

class TCbwAnimationEffect {

         bool__fastcall IsAtEnd();

         CbwObjectsFAnimationObjects; // 相关对象

 

         cv::Mat__fastcall Object2Mat(TCbwObject * object, double ratio = 1);

         int__fastcall GetRepeateTime();

protected:

         vector<OBJECTMAT>FDestMats;

         intFCurrentIndex; // 当前帧索引

         intFPeriodLength; // 周期长度,指动画一个周期内的帧数

         intFPosition; // 当前位置,指动画累加索引位置

         intFWidth, FHeight; // 长宽尺寸,指显示限制

 

public:

         CbwEffectTypeEffectType;

         ENHANCE_INFOEnhanceOption; // 增强选项

         TIMER_INFOTimerOption; // 计时选项

 

         __fastcallTCbwAnimationEffect();

         staticTCbwAnimationEffect * Build();

 

         void__fastcall Assign(TCbwAnimationEffect * other);

 

         void__fastcall AddToXmlNode(CbwXmlNode * node);

         void__fastcall GetFromXmlNode(CbwXmlNode * node);

 

         void__fastcall First();

         void__fastcall Next();

         void__fastcall SetRelativeObject(CbwObjects relativeObjects,

                   TPaintBox* pb, TScrollBox * scrollBox);

         void__fastcall SetBounds(int width, int height);

 

         void__fastcall Draw(HWND wnd, BYTE * backData, int width, int height);

 

         cv::MatCurrentMat;

         __propertybool Eof = {read = IsAtEnd};

 

protected:

         virtualTRect __fastcall BuildDisplayRect(OBJECTMAT * m);

         virtualvoid __fastcall BuildDisplayMat(cv::Mat& destMat, cv::Mat& srcMat);

         virtualvoid __fastcall BuildMaskMat(cv::Mat& destMat, cv::Mat& srcMat);

};

 

核心实现代码为:

__fastcallTCbwAnimationEffect::TCbwAnimationEffect() {

         TimerOption.StartMode= ttsClick;

         TimerOption.Delay= 0;

         TimerOption.PeriodMode= ttpNormal;

         TimerOption.RepeatMode= ttrNone;

         TimerOption.QuickBackAfterPlay= false;

         EffectType= cetBase;

}

 

TCbwAnimationEffect *TCbwAnimationEffect::Build() {

         returnnew TCbwAnimationEffect;

}

 

TRect __fastcallTCbwAnimationEffect::BuildDisplayRect(OBJECTMAT * m) {

         TRectresult(m->LeftTopPosition.x, m->LeftTopPosition.y,

                   m->LeftTopPosition.x+ m->Mat.cols, m->LeftTopPosition.y + m->Mat.rows);

         returnresult;

}

 

void __fastcall TCbwAnimationEffect::BuildDisplayMat(cv::Mat&destMat,

         cv::Mat&srcMat) {

         destMat= srcMat.clone();

}

 

void __fastcallTCbwAnimationEffect::BuildMaskMat(cv::Mat& destMat,

         cv::Mat&srcMat) {

         destMat= srcMat.clone();

}

 

void __fastcallTCbwAnimationEffect::Draw(HWND wnd, BYTE * backData, int width,

         intheight) {

         cv::MatbackGndMat(height, width, CV_8UC3); // 背景

         GlobalOpenCVObject->CopyRGBDatasToMat(backGndMat,backData, width,

                   height,true);

 

         CBW_ITERATOR(vector<OBJECTMAT>,FDestMats) {

                   OBJECTMAT* animationObject = &(*it);

                   //以下取得待显示的区域、内容

                   TRectanimationDisplayRect = BuildDisplayRect(animationObject); // 目标区域

 

                   cv::MatanimationDisplayMat =

                            cv::Mat::zeros(animationDisplayRect.Height(),

                            animationDisplayRect.Width(),animationObject->Mat.type());

                   BuildDisplayMat(animationDisplayMat,animationObject->Mat); // 待显示内容

 

                   cv::MatmaskMat = cv::Mat::zeros(animationObject->Mask.rows,

                            animationObject->Mask.cols,animationObject->Mask.type());

                   BuildMaskMat(maskMat,animationObject->Mask); // Mask内容

 

                   TRectsuitableDisplayRect; // 真正的目标显示区域

                   suitableDisplayRect.left= max(0, int(animationDisplayRect.left));

                   suitableDisplayRect.top= max(0, int(animationDisplayRect.top));

                   suitableDisplayRect.right= min(int(animationDisplayRect.right), width);

                   suitableDisplayRect.bottom= min(int(animationDisplayRect.bottom),

                            height);

 

                   TRectsuitableRectInMat(0, 0, suitableDisplayRect.Width(),

                            suitableDisplayRect.Height());

                   intdeltaL =

                            max(0,int(suitableDisplayRect.left - animationDisplayRect.left));

                   if(suitableDisplayRect.left != animationDisplayRect.left) {

                            suitableRectInMat.left+= deltaL;

                            suitableRectInMat.right+= deltaL;

                   }

                   intdeltaT =

                            max(0,int(suitableDisplayRect.top - animationDisplayRect.top));

                   if(suitableDisplayRect.top != animationDisplayRect.top) {

                            suitableRectInMat.top+= deltaT;

                            suitableRectInMat.bottom+= deltaT;

                   }

 

                   cv::MatdestPartMat =

                            animationDisplayMat(cv::Rect(suitableRectInMat.left,

                            suitableRectInMat.top,suitableRectInMat.Width(),

                            suitableRectInMat.Height()));

                   cv::MatbackgndPartMat = // 目标背景区域相应矩阵

                            backGndMat(cv::Rect(suitableDisplayRect.left,

                            suitableDisplayRect.top,suitableDisplayRect.Width(),

                            suitableDisplayRect.Height()));

                   cv::MatmaskPartMat =

                            maskMat(cv::Rect(deltaL,deltaT, suitableDisplayRect.Width(),

                            suitableDisplayRect.Height()));

                   destPartMat.copyTo(backgndPartMat,maskPartMat);

         }

         GlobalOpenCVObject->PreviewMat(wnd,backGndMat, width, height);

}

 

void __fastcallTCbwAnimationEffect::Assign(TCbwAnimationEffect * other) {

         TimerOption.StartMode= other->TimerOption.StartMode;

         TimerOption.Delay= other->TimerOption.Delay;

         TimerOption.PeriodMode= other->TimerOption.PeriodMode;

         TimerOption.RepeatMode= other->TimerOption.RepeatMode;

         TimerOption.QuickBackAfterPlay= other->TimerOption.QuickBackAfterPlay;

}

 

bool __fastcallTCbwAnimationEffect::IsAtEnd() {

         boolresult = (FPosition >= FPeriodLength * GetRepeateTime());

         returnresult;

}

 

void __fastcall TCbwAnimationEffect::First(){

         FPosition= 0;

         FCurrentIndex= 0;

}

 

void __fastcall TCbwAnimationEffect::Next(){

         ++FPosition;

         FCurrentIndex= FPosition % FPeriodLength;

}

 

cv::Mat __fastcallTCbwAnimationEffect::Object2Mat(TCbwObject * object,

         doubleratio) {

         TCanvas* oldCanvas = object->Canvas;

         Graphics::TBitmap* bitmap = new Graphics::TBitmap;

         bitmap->PixelFormat= pf24bit;

         bitmap->Width= object->Width;

         bitmap->Height= object->Height;

 

         TCanvas* canvas = bitmap->Canvas;

         boolallowDraw = object->AllowDraw;

         boololdDrawBorderFlag = object->DrawBorderFlag;

         object->AllowDraw= false; {

                   TRestoreleft(object, "Left", 0);

                   TRestoretop(object, "Top", 0);

                   object->Canvas= canvas;

                   object->AllowDraw= allowDraw;

                   object->DrawBorderFlag= false;

                   object->Draw();

                   object->AllowDraw= false;

         }object->Canvas = oldCanvas;

         object->AllowDraw= allowDraw;

         object->DrawBorderFlag= oldDrawBorderFlag;

         BYTE* backData = THelper::Graphics::GetBitmapData(bitmap);

         cv::Matresult;

         GlobalOpenCVObject->CopyRGBDatasToMat(result,backData, bitmap->Width,

                   bitmap->Height,true);

         deletebitmap;

         deletebackData;

         returnresult;

}

 

void __fastcallTCbwAnimationEffect::OBJECTMAT::BuildMask(int height, int width)

{

         Mask= cv::Mat(height, width, CV_8UC1);

         BYTE* pSrc = Mat.data;

         BYTE* pDst = Mask.data;

         for(int i = height * width - 1; i >= 0; --i) {

                   BYTEB = *pSrc++;

                   BYTEG = *pSrc++;

                   BYTER = *pSrc++;

                   *pDst++= (B == 0xFF && G == 0xFF && R == 0xFF) ? 0 : 255;

         }

}

 

void __fastcallTCbwAnimationEffect::SetRelativeObject

         (CbwObjectsrelativeObjects, TPaintBox * pb, TScrollBox * scrollBox) {

         CBW_ITERATOR(CbwObjects,relativeObjects) {

                   cv::Matmat = Object2Mat(*it);

                   TPointlt = TPoint((*it)->Left, (*it)->Top);

                   lt= pb->ClientToScreen(lt);

                   lt= scrollBox->ScreenToClient(lt);

                   OBJECTMATm;

                   m.Mat= mat;

                   m.LeftTopPosition= lt;

                   m.Object= *it;

                   m.BuildMask((*it)->Height,(*it)->Width);

                   FDestMats.push_back(m);

         }

         FPeriodLength= 50;

         FCurrentIndex= 0;

         FPosition= 0;

}

 

void __fastcallTCbwAnimationEffect::SetBounds(int width, int height) {

         FWidth= width;

         FHeight= height;

}

为方便调用处逻辑简单,可采用:

typedef TCbwAnimationEffect *(*BuildEffectObject)(); // 智能构造函数

typedef std::map<int,BuildEffectObject>EffectObjectMap; // 构造各图元对象映射

#define CREATEEFFECTOBJECTif(!CbwEffectObjectMap) CbwEffectObjectMap = new EffectObjectMap;  (*CbwEffectObjectMap)

         CREATEEFFECTOBJECT[cetBase]= TCbwAnimationEffect::Build;

         CREATEEFFECTOBJECT[cetAppear]= TCbwAnimationEffect_Appear::Build;

         CREATEEFFECTOBJECT[cetFadeOut]= TCbwAnimationEffect_FadeOut::Build;

         CREATEEFFECTOBJECT[cetFlyIn]= TCbwAnimationEffect_FlyIn::Build;

 

这样,调用时,简单处理即可:

         if(!(*CbwEffectObjectMap)[effectType]) {

                   THelper::Util::MessageBox(L"本动画效果尚未实现,请稍候!", false);

             return;

         }

         TCbwAnimationEffect* effectItem = (*CbwEffectObjectMap)[effectType](); // 根据类型创建动画对象

 

三、调用

调用,先处理用户选中某个对象后的动画类型逻辑

void __fastcall TForm::AddEffect(TdxRibbonGalleryGroupItem*AItem) {

         if(cSelectedObjects->MetaNumber== 0) return;

         inteffectType = AItem->ImageIndex + 1;

         if(!(*CbwEffectObjectMap)[effectType]) {

                   THelper::Util::MessageBox(L"本动画效果尚未实现,请稍候!", false);

             return;

         }

         TCbwAnimationEffect* effectItem = (*CbwEffectObjectMap)[effectType](); // 根据类型创建动画对象

         effectItem->SetRelativeObject(cSelectedObjects->SubObjects,PaintBox, ScrollBox);

         effectItem->SetBounds(ScrollBox->Width,ScrollBox->Height);

         Graphics::TBitmap* bitmap = new Graphics::TBitmap;

         bitmap->PixelFormat= pf24bit;

         bitmap->Width= ScrollBox->Width;

         bitmap->Height= ScrollBox->Height;

 

         RECTdisplayRect = Rect(ScrollBox->HorzScrollBar->Position,

                   ScrollBox->VertScrollBar->Position,ScrollBox->HorzScrollBar->Position +

                   ScrollBox->Width,ScrollBox->VertScrollBar->Position +

                   ScrollBox->Height);

 

         Graphics::TBitmap* FPreviewBitmap = new Graphics::TBitmap;

         FPreviewBitmap->PixelFormat= pf24bit;

         FPreviewBitmap->Width= PaintBox->Width;

         FPreviewBitmap->Height= PaintBox->Height;

         TCanvas* canvas = FPreviewBitmap->Canvas;

         canvas->Rectangle(0,0, 10000, 10000);

         CBW_ITERATOR(CbwObjects,Objects)(*it)->Canvas = canvas;

 

         CBW_ITERATOR(CbwObjects,Objects) {

                   TCbwObject* object = *it;

                   if(!CanObjectBeVisible(object) || !object->CanContinueWithRect

                            (displayRect,CBW_CONTINUE_DRAW) || object->Selected)

                            continue;

                   object->Draw();

         }

         PostPaint(canvas);

         bitmap->Canvas->CopyRect(Rect(0,0, bitmap->Width, bitmap->Height), canvas,

                   displayRect);

         CBW_ITERATOR(CbwObjects,Objects)(*it)->Canvas = PaintBox->Canvas;

 

         TRestoreApplicationCurrentStatus(TGraphApp::CurrentStatus, cfsAnimation);

         BYTE* backData = THelper::Graphics::GetBitmapData(bitmap);

         effectItem->First();

         while(!effectItem->Eof){

                   effectItem->Draw(ScrollBox->Handle,backData, bitmap->Width, bitmap->Height);

                   effectItem->Next();

                   Sleep(10);

         }

         deletebackData;

         deleteFPreviewBitmap;

         deletebitmap;

         deleteeffectItem;

}

剩下的事情就是针对各动画类型进行细化。今天先实现一种:淡出动画效果

 

四、淡出动画效果

参考PPT效果,淡出是慢慢出现对象,这用OpenCV控制Mat的各点即可简单实现

在基类的基础上,再实现各种动画效果,应该算是比较轻松的了,对于淡出效果而言,无需变动位置,只控制显示像素,直接重载BuildDisplayMat,根据当前进度处理各像素亮度。

 

/**

 *@class TCbwAnimationEffect_ FadeOut

 *@brief 淡出动画类

 *

 * 淡出动画

 *@author 陈斌文

 *@version 1.0

 *@date 2015-03-03

 *@QQ: 282397369

 */

class TCbwAnimationEffect_FadeOut : publicTCbwAnimationEffect { // 淡出

         typedefTCbwAnimationEffect inherited;

         virtualvoid __fastcall BuildDisplayMat(cv::Mat& destMat, cv::Mat& srcMat);

public:

         __fastcallTCbwAnimationEffect_FadeOut();

         staticTCbwAnimationEffect * Build();

};

 

// ***************************** 淡出效果**************************************

__fastcallTCbwAnimationEffect_FadeOut::TCbwAnimationEffect_FadeOut()

         :TCbwAnimationEffect() {

         EffectType= cetFadeOut;

}

 

TCbwAnimationEffect *TCbwAnimationEffect_FadeOut::Build() {

         returnnew TCbwAnimationEffect_FadeOut;

}

 

void __fastcallTCbwAnimationEffect_FadeOut::BuildDisplayMat(cv::Mat& destMat,

         cv::Mat&srcMat) {

         for(int y = 0; y < destMat.rows; y++) {

                   for(int x = 0; x < destMat.cols; x++) {

                            for(int c = 0; c < 3; c++) {

                                     BYTEvalue = srcMat.at<cv::Vec3b>(y, x)[c];

                                     value= 255 - FCurrentIndex / double(FPeriodLength) *

                                               (255- value);

                                     destMat.at<cv::Vec3b>(y,x)[c] =

                                               cv::saturate_cast<uchar>(value);

                            }

                   }

         }

}

// ***************************** 淡出效果**************************************

技术分享

风火轮 – 动画效果

标签:opencv   风火轮   

原文地址:http://blog.csdn.net/arwen/article/details/44039999

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!