add fps modifier for animation

This commit is contained in:
Jinhao 2015-02-16 06:59:56 +08:00
parent 274155b1da
commit 4385ac623d
4 changed files with 103 additions and 77 deletions

View File

@ -1,6 +1,7 @@
/* /*
* An Animation Implementation * An Animation Implementation
* Copyright(C) 2003-2013 Jinhao(cnjinhao@hotmail.com) * Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com)
* *
* Distributed under the Boost Software License, Version 1.0. * Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at * (See accompanying file LICENSE_1_0.txt or copy at
@ -27,15 +28,13 @@ namespace nana
friend class animation; friend class animation;
public: public:
/// function which builds frames. /// function which builds frames.
typedef std::function<bool(std::size_t pos, paint::graphics&, nana::size&)> framebuilder; using framebuilder = std::function<bool(std::size_t pos, paint::graphics&, nana::size&)>;
struct impl; struct impl;
public: public:
frameset(); frameset();
void push_back(const paint::image&); ///< Inserts frames at the end. void push_back(paint::image); ///< Inserts frames at the end.
void push_back(paint::image&&); void push_back(framebuilder fb, std::size_t length); ///< Insters a framebuilder and the number of frames that it generates.
void push_back(framebuilder& fb, std::size_t length); ///< Insters a framebuilder and the number of frames that it generates.
void push_back(framebuilder&& fb, std::size_t length); ///< Insters a framebuilder and the number of frames that it generates.
private: private:
std::shared_ptr<impl> impl_; std::shared_ptr<impl> impl_;
}; };
@ -51,9 +50,9 @@ namespace nana
struct impl; struct impl;
class performance_manager; class performance_manager;
public: public:
animation(); animation(std::size_t fps = 23);
void push_back(const frameset& frms); void push_back(frameset frms);
/* /*
void branch(const std::string& name, const frameset& frms) void branch(const std::string& name, const frameset& frms)
{ {
@ -75,6 +74,9 @@ namespace nana
void pause(); void pause();
void output(window wd, const nana::point& pos); void output(window wd, const nana::point& pos);
void fps(std::size_t n);
std::size_t fps() const;
private: private:
impl * impl_; impl * impl_;
}; };

View File

@ -44,7 +44,6 @@ namespace nana
widget * widget_{nullptr}; widget * widget_{nullptr};
nana::paint::graphics* graph_{nullptr}; nana::paint::graphics* graph_{nullptr};
unsigned draw_width_{static_cast<unsigned>(-1)}; unsigned draw_width_{static_cast<unsigned>(-1)};
//bool has_value_{true}; //deprecated
bool unknown_{false}; bool unknown_{false};
unsigned max_{100}; unsigned max_{100};
unsigned value_{0}; unsigned value_{0};

View File

@ -1,6 +1,7 @@
/* /*
* An Animation Implementation * An Animation Implementation
* Copyright(C) 2003-2013 Jinhao(cnjinhao@hotmail.com) * Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com)
* *
* Distributed under the Boost Software License, Version 1.0. * Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at * (See accompanying file LICENSE_1_0.txt or copy at
@ -48,11 +49,7 @@ namespace nana
std::size_t length; std::size_t length;
std::function<bool(std::size_t, paint::graphics&, nana::size&)> frbuilder; std::function<bool(std::size_t, paint::graphics&, nana::size&)> frbuilder;
framebuilder(const std::function<bool(std::size_t, paint::graphics&, nana::size&)>& f, std::size_t l) framebuilder(std::function<bool(std::size_t, paint::graphics&, nana::size&)> f, std::size_t l)
: length(l), frbuilder(f)
{}
framebuilder(std::size_t l, std::function<bool(std::size_t, paint::graphics&, nana::size)>&& f)
: length(l), frbuilder(std::move(f)) : length(l), frbuilder(std::move(f))
{} {}
}; };
@ -65,28 +62,16 @@ namespace nana
framebuilder framebuilder
}; };
frame(const paint::image& r) frame(paint::image img)
: type(kind::oneshot) : type(kind::oneshot)
{ {
u.oneshot = new paint::image(r); u.oneshot = new paint::image(std::move(img));
} }
frame(paint::image&& r) frame(std::function<bool(std::size_t, paint::graphics&, nana::size&)> frbuilder, std::size_t length)
: type(kind::oneshot)
{
u.oneshot = new paint::image(std::move(r));
}
frame(const std::function<bool(std::size_t, paint::graphics&, nana::size&)>& frbuilder, std::size_t length)
: type(kind::framebuilder) : type(kind::framebuilder)
{ {
u.frbuilder = new framebuilder(frbuilder, length); u.frbuilder = new framebuilder(std::move(frbuilder), length);
}
frame(std::function<bool(std::size_t, paint::graphics&, nana::size&)>&& frbuilder, std::size_t length)
: type(kind::framebuilder)
{
u.frbuilder = new framebuilder(frbuilder, length);
} }
frame(const frame& r) frame(const frame& r)
@ -323,29 +308,15 @@ namespace nana
: impl_(new impl) : impl_(new impl)
{} {}
void frameset::push_back(const paint::image& m) void frameset::push_back(paint::image img)
{ {
bool located = impl_->this_frame != impl_->frames.end(); bool located = impl_->this_frame != impl_->frames.end();
impl_->frames.emplace_back(m); impl_->frames.emplace_back(std::move(img));
if(false == located) if(false == located)
impl_->this_frame = impl_->frames.begin(); impl_->this_frame = impl_->frames.begin();
} }
void frameset::push_back(paint::image&& m) void frameset::push_back(framebuilder fb, std::size_t length)
{
impl_->frames.emplace_back(std::move(m));
if(1 == impl_->frames.size())
impl_->this_frame = impl_->frames.begin();
}
void frameset::push_back(framebuilder&fb, std::size_t length)
{
impl_->frames.emplace_back(fb, length);
if(1 == impl_->frames.size())
impl_->this_frame = impl_->frames.begin();
}
void frameset::push_back(framebuilder&& fb, std::size_t length)
{ {
impl_->frames.emplace_back(std::move(fb), length); impl_->frames.emplace_back(std::move(fb), length);
if(1 == impl_->frames.size()) if(1 == impl_->frames.size())
@ -365,10 +336,14 @@ namespace nana
std::size_t active; //The number of active animations std::size_t active; //The number of active animations
std::shared_ptr<std::thread> thread; std::shared_ptr<std::thread> thread;
std::size_t fps;
double interval; //milliseconds between 2 frames.
double performance_parameter; double performance_parameter;
}; };
thread_variable * insert(impl* p); void insert(impl* p);
void set_fps(impl*, std::size_t new_fps);
void close(impl* p); void close(impl* p);
bool empty() const; bool empty() const;
private: private:
@ -380,8 +355,9 @@ namespace nana
struct animation::impl struct animation::impl
{ {
bool looped; bool looped{false};
volatile bool paused; volatile bool paused{true};
std::size_t fps;
std::list<frameset> framesets; std::list<frameset> framesets;
std::map<std::string, branch_t> branches; std::map<std::string, branch_t> branches;
@ -399,17 +375,21 @@ namespace nana
static performance_manager * perf_manager; static performance_manager * perf_manager;
impl() impl(std::size_t fps)
: looped(false), paused(true) : fps(fps)
{ {
state.this_frameset = framesets.begin(); state.this_frameset = framesets.begin();
if (!perf_manager)
{ {
nana::internal_scope_guard lock; nana::internal_scope_guard lock;
if(nullptr == perf_manager) if (!perf_manager)
perf_manager = new performance_manager; {
auto pm = new performance_manager;
perf_manager = pm;
}
} }
thr_variable = perf_manager->insert(this); perf_manager->insert(this);
} }
~impl() ~impl()
@ -457,46 +437,78 @@ namespace nana
};//end struct animation::impl };//end struct animation::impl
//class animation::performance_manager //class animation::performance_manager
auto animation::performance_manager::insert(impl* p) -> thread_variable * void animation::performance_manager::insert(impl* p)
{ {
std::lock_guard<decltype(mutex_)> lock(mutex_); std::lock_guard<decltype(mutex_)> lock(mutex_);
for(auto thr : threads_) for(auto thr : threads_)
{ {
std::lock_guard<decltype(thr->mutex)> privlock(thr->mutex); std::lock_guard<decltype(thr->mutex)> privlock(thr->mutex);
if(thr->performance_parameter / (thr->animations.size() + 1) <= 43.3) if ((thr->fps == p->fps) && (thr->performance_parameter / (thr->animations.size() + 1) <= 43.3))
{ {
p->thr_variable = thr;
thr->animations.push_back(p); thr->animations.push_back(p);
return thr; return;
} }
} }
auto thr = new thread_variable; auto thr = new thread_variable;
thr->animations.push_back(p); thr->animations.push_back(p);
thr->performance_parameter = 0.0; thr->performance_parameter = 0.0;
thr->fps = p->fps;
thr->interval = 1000.0 / double(p->fps);
thr->thread = std::make_shared<std::thread>([this, thr]() thr->thread = std::make_shared<std::thread>([this, thr]()
{ {
_m_perf_thread(thr); _m_perf_thread(thr);
}); });
threads_.push_back(thr); threads_.push_back(thr);
return thr; p->thr_variable = thr;
}
void animation::performance_manager::set_fps(impl* p, std::size_t new_fps)
{
if (p->fps == new_fps)
return;
std::lock_guard<decltype(mutex_)> lock(mutex_);
auto i = std::find(threads_.begin(), threads_.end(), p->thr_variable);
if (i == threads_.end())
return;
p->fps = new_fps;
auto thr = *i;
//Simply modify the fps parameter if the thread just has one animation.
if (thr->animations.size() == 1)
{
thr->fps = new_fps;
thr->interval = 1000.0 / double(new_fps);
return;
}
std::lock_guard<decltype(thr->mutex)> privlock(thr->mutex);
auto u = std::find(thr->animations.begin(), thr->animations.end(), p);
if (u != thr->animations.end())
thr->animations.erase(u);
p->thr_variable = nullptr;
insert(p);
} }
void animation::performance_manager::close(impl* p) void animation::performance_manager::close(impl* p)
{ {
std::lock_guard<decltype(mutex_)> lock(mutex_); std::lock_guard<decltype(mutex_)> lock(mutex_);
for(auto thr : threads_) auto i = std::find(threads_.begin(), threads_.end(), p->thr_variable);
{ if (i == threads_.end())
std::lock_guard<decltype(thr->mutex)> privlock(thr->mutex); return;
auto i = std::find(thr->animations.begin(), thr->animations.end(), p); auto thr = *i;
if(i != thr->animations.end()) std::lock_guard<decltype(thr->mutex)> privlock(thr->mutex);
{
thr->animations.erase(i); auto u = std::find(thr->animations.begin(), thr->animations.end(), p);
return; if(u != thr->animations.end())
} thr->animations.erase(u);
}
} }
bool animation::performance_manager::empty() const bool animation::performance_manager::empty() const
@ -542,8 +554,8 @@ namespace nana
if(thrvar->active) if(thrvar->active)
{ {
thrvar->performance_parameter = tmpiece.calc(); thrvar->performance_parameter = tmpiece.calc();
if(thrvar->performance_parameter < 43.4) if(thrvar->performance_parameter < thrvar->interval)
nana::system::sleep(static_cast<unsigned>(43.4 - thrvar->performance_parameter)); nana::system::sleep(static_cast<unsigned>(thrvar->interval - thrvar->performance_parameter));
} }
else else
{ {
@ -557,15 +569,15 @@ namespace nana
} }
//end class animation::performance_manager //end class animation::performance_manager
animation::animation() animation::animation(std::size_t fps)
: impl_(new impl) : impl_(new impl(fps))
{ {
} }
void animation::push_back(const frameset& frms) void animation::push_back(frameset frms)
{ {
impl_->framesets.emplace_back(frms); impl_->framesets.emplace_back(std::move(frms));
if(1 == impl_->framesets.size()) if(1 == impl_->framesets.size())
impl_->state.this_frameset = impl_->framesets.begin(); impl_->state.this_frameset = impl_->framesets.begin();
} }
@ -634,6 +646,19 @@ namespace nana
} }
output.points.push_back(pos); output.points.push_back(pos);
} }
void animation::fps(std::size_t n)
{
if (n == impl_->fps)
return;
impl::perf_manager->set_fps(impl_, n);
}
std::size_t animation::fps() const
{
return impl_->fps;
}
//end class animation //end class animation

View File

@ -108,7 +108,7 @@ namespace nana
{ {
rectangle r = graph.size(); rectangle r = graph.size();
graph.gradual_rectangle(r, colors::button_face_shadow_end, colors::button_face_shadow_start, true); graph.gradual_rectangle(r, colors::button_face_shadow_end, colors::button_face_shadow_start, true);
::nana::color lt{ 0x80, 0x80, 0x80 }, rb{colors::white}; ::nana::color lt{ colors::gray }, rb{colors::white};
graph.frame_rectangle(r, lt, lt, rb, rb); graph.frame_rectangle(r, lt, lt, rb, rb);
} }