1 /*
2  Copyright (C) 2010-2014 Kristian Duske
3 
4  This file is part of TrenchBroom.
5 
6  TrenchBroom is free software: you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation, either version 3 of the License, or
9  (at your option) any later version.
10 
11  TrenchBroom is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  GNU General Public License for more details.
15 
16  You should have received a copy of the GNU General Public License
17  along with TrenchBroom. If not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 #include "Animation.h"
21 #include "View/AnimationCurve.h"
22 
23 #include <algorithm>
24 #include <cassert>
25 
26 #include <wx/app.h>
27 #include <wx/timer.h>
28 
29 namespace TrenchBroom {
30     namespace View {
freeType()31         Animation::Type Animation::freeType() {
32             static Type type = 0;
33             return type++;
34         }
35 
Animation(const Type type,const Curve curve,const wxLongLong duration)36         Animation::Animation(const Type type, const Curve curve, const wxLongLong duration) :
37         m_type(type),
38         m_curve(NULL),
39         m_duration(duration),
40         m_elapsed(0),
41         m_progress(0.0) {
42             assert(m_duration > 0);
43             switch (curve) {
44                 case Curve_EaseInEaseOut:
45                     m_curve = new EaseInEaseOutAnimationCurve(m_duration);
46                     break;
47                 case Curve_Flat:
48                     m_curve = new FlatAnimationCurve();
49                     break;
50             }
51         }
52 
~Animation()53         Animation::~Animation() {
54             delete m_curve;
55             m_curve = NULL;
56         }
57 
type() const58         Animation::Type Animation::type() const {
59             return m_type;
60         }
61 
step(const wxLongLong delta)62         bool Animation::step(const wxLongLong delta) {
63             m_elapsed = std::min(m_elapsed + delta, m_duration);
64             m_progress = m_elapsed.ToDouble() / m_duration.ToDouble();
65             return m_elapsed >= m_duration;
66         }
67 
update()68         void Animation::update() {
69             doUpdate(m_progress);
70         }
71 
ExecutableAnimation(const Animation::List & animations)72         ExecutableAnimation::ExecutableAnimation(const Animation::List& animations) :
73         m_animations(animations) {}
74 
execute()75         void ExecutableAnimation::execute() {
76             Animation::List::const_iterator it, end;
77             for (it = m_animations.begin(), end = m_animations.end(); it != end; ++it) {
78                 Animation& animation = **it;
79                 animation.update();
80             }
81         }
82 
AnimationManager()83         AnimationManager::AnimationManager() :
84         m_lastTime(wxGetLocalTimeMillis()) {
85             Run();
86         }
87 
runAnimation(Animation * animation,const bool replace)88         void AnimationManager::runAnimation(Animation* animation, const bool replace) {
89             assert(animation != NULL);
90 
91             Animation::List& list = m_animations[animation->type()];
92             if (replace)
93                 list.clear();
94             list.push_back(Animation::Ptr(animation));
95         }
96 
Entry()97         wxThread::ExitCode AnimationManager::Entry() {
98             while (!TestDestroy()) {
99                 const wxLongLong elapsed = wxGetLocalTimeMillis() - m_lastTime;
100 
101                 Animation::List updateAnimations;
102                 if (!m_animations.empty()) {
103                     AnimationMap::iterator mapIt = m_animations.begin();
104                     while (mapIt != m_animations.end()) {
105                         Animation::List& list = mapIt->second;
106                         Animation::List::iterator listIt = list.begin();
107                         while (listIt != list.end()) {
108                             Animation::Ptr animation = *listIt;
109                             if (animation->step(elapsed))
110                                 listIt = list.erase(listIt);
111                             updateAnimations.push_back(animation);
112                             if (listIt != list.end())
113                                 ++listIt;
114                         }
115 
116                         if (list.empty())
117                             m_animations.erase(mapIt++);
118                         else
119                             ++mapIt;
120                     }
121                 }
122                 m_lastTime += elapsed;
123 
124                 if (!TestDestroy() && wxTheApp != NULL && !updateAnimations.empty()) {
125                     ExecutableEvent::Executable::Ptr executable(new ExecutableAnimation(updateAnimations));
126                     ExecutableEvent* event = new ExecutableEvent(executable);
127                     wxTheApp->QueueEvent(event);
128                 }
129 
130                 Sleep(20);
131             }
132 
133             return static_cast<ExitCode>(0);
134         }
135     }
136 }
137