#include "../../frame/draw_frame.h"
#include "../../interaction/interaction_aggregator.h"
+#include "../text/text_producer.h"
namespace caspar { namespace core { namespace scene {
{
}
+struct timeline
+{
+ std::map<int64_t, keyframe> keyframes;
+
+ void on_frame(int64_t frame)
+ {
+ auto before = --keyframes.upper_bound(frame);
+ bool found_before = before != keyframes.end() && before->first < frame;
+ auto after = keyframes.upper_bound(frame);
+ bool found_after = after != keyframes.end() && after->first > frame;
+ auto exact_frame = keyframes.find(frame);
+ bool found_exact_frame = exact_frame != keyframes.end();
+
+ if (found_exact_frame)
+ {
+ exact_frame->second.on_destination_frame();
+
+ auto next_frame = ++exact_frame;
+
+ if (next_frame != keyframes.end() && next_frame->second.on_start_animate)
+ next_frame->second.on_start_animate();
+ }
+ else if (found_after)
+ {
+ int64_t start_frame = 0;
+
+ if (found_before)
+ {
+ start_frame = before->first;
+ }
+
+ if (after->second.on_start_animate && frame == 0)
+ after->second.on_start_animate();
+ else if (after->second.on_animate_to)
+ after->second.on_animate_to(start_frame, frame);
+ }
+ }
+};
+
struct scene_producer::impl
{
constraints pixel_constraints_;
interaction_aggregator aggregator_;
binding<int64_t> frame_number_;
std::map<std::wstring, std::shared_ptr<parameter_holder_base>> parameters_;
+ std::map<void*, timeline> timelines_;
impl(int width, int height)
: pixel_constraints_(width, height)
parameters_.insert(std::make_pair(boost::to_lower_copy(name), param));
}
+ void store_keyframe(void* timeline_identity, const keyframe& k)
+ {
+ timelines_[timeline_identity].keyframes.insert(std::make_pair(k.destination_frame, k));
+ }
+
binding<int64_t> frame()
{
return frame_number_;
draw_frame render_frame()
{
+ BOOST_FOREACH(auto& timeline, timelines_)
+ timeline.second.on_frame(frame_number_.get());
+
std::vector<draw_frame> frames;
BOOST_FOREACH(auto& layer, layers_)
impl_->store_parameter(name, param);
}
+void scene_producer::store_keyframe(void* timeline_identity, const keyframe& k)
+{
+ impl_->store_keyframe(timeline_identity, k);
+}
+
spl::shared_ptr<frame_producer> create_dummy_scene_producer(const spl::shared_ptr<class frame_factory>& frame_factory, const video_format_desc& format_desc, const std::vector<std::wstring>& params)
{
if (params.size() < 1 || !boost::iequals(params.at(0), L"[SCENE]"))
auto scene = spl::make_shared<scene_producer>(format_desc.width, format_desc.height);
- binding<double> text_width(10);
+ text::text_info text_info;
+ text_info.font = L"Arial";
+ text_info.size = 62;
+ text_info.color.r = 1;
+ text_info.color.g = 1;
+ text_info.color.b = 1;
+ text_info.color.a = 0.5;
+ auto text_area = text_producer::create(frame_factory, 0, 0, L"a", text_info, 1280, 720, false);
+
+ auto text_width = text_area->pixel_constraints().width;
binding<double> padding(1);
binding<double> panel_width = padding + text_width + padding;
- binding<double> panel_height(50);
+ binding<double> panel_height = padding + text_area->pixel_constraints().height + padding;
auto subscription = panel_width.on_change([&]
{
CASPAR_LOG(info) << "Panel width: " << panel_width.get();
});
- text_width.set(20);
- text_width.set(10);
padding.set(2);
- text_width.set(20);
auto create_param = [](std::wstring elem) -> std::vector<std::wstring>
{
return result;
};
- auto& car_layer = scene->create_layer(create_producer(frame_factory, format_desc, create_param(L"car")));
- car_layer.hidden = scene->frame() % 50 > 25 || !(scene->frame() < 1000);
+ //auto& car_layer = scene->create_layer(create_producer(frame_factory, format_desc, create_param(L"car")));
+ //car_layer.hidden = scene->frame() % 50 > 25 || !(scene->frame() < 1000);
std::vector<std::wstring> sub_params;
sub_params.push_back(L"[FREEHAND]");
sub_params.push_back(L"640");
auto& upper_right = scene->create_layer(create_producer(frame_factory, format_desc, create_param(L"scene/upper_right")));
auto& lower_left = scene->create_layer(create_producer(frame_factory, format_desc, create_param(L"scene/lower_left")));
auto& lower_right = scene->create_layer(create_producer(frame_factory, format_desc, create_param(L"scene/lower_right")));
+ auto& text_layer = scene->create_layer(text_area);
/*
binding<double> panel_x = (scene->frame()
+ 40.0)
.transformed([](double v) { return std::floor(v); }); // snap to pixels instead of subpixels
*/
- tweener tween(L"easeinoutsine");
- binding<double> panel_x = when(scene->frame() < 50)
+ tweener tween(L"easeoutbounce");
+ binding<double> panel_x(0);
+
+ scene->add_keyframe(panel_x, -panel_width, 0);
+ scene->add_keyframe(panel_x, 300.0, 50, L"easeinoutsine");
+ scene->add_keyframe(panel_x, 300.0, 50 * 4);
+ scene->add_keyframe(panel_x, 1000.0, 50 * 5, L"easeinoutsine");
+ //panel_x = delay(panel_x, add_tween(panel_x, scene->frame(), 200.0, int64_t(50), L"linear"), scene->frame(), int64_t(100));
+ /*binding<double> panel_x = when(scene->frame() < 50)
.then(scene->frame().as<double>().transformed([tween](double t) { return tween(t, 0.0, 200, 50); }))
- .otherwise(200.0);
+ .otherwise(200.0);*/
//binding<double> panel_y = when(car_layer.hidden).then(500.0).otherwise(-panel_x + 300);
binding<double> panel_y(500.0);
+ scene->add_keyframe(panel_y, panel_y.get(), 50 * 4);
+ scene->add_keyframe(panel_y, 720.0, 50 * 5, L"easeinexpo");
upper_left.position.x = panel_x;
upper_left.position.y = panel_y;
upper_right.position.x = upper_left.position.x + upper_left.producer.get()->pixel_constraints().width + panel_width;
lower_left.position.y = upper_left.position.y + upper_left.producer.get()->pixel_constraints().height + panel_height;
lower_right.position.x = upper_right.position.x;
lower_right.position.y = lower_left.position.y;
+ text_layer.position.x = upper_left.position.x + upper_left.producer.get()->pixel_constraints().width + padding;
+ text_layer.position.y = upper_left.position.y + upper_left.producer.get()->pixel_constraints().height + padding + text_area->current_bearing_y().as<double>();
+
+ text_area->text().bind(scene->create_parameter<std::wstring>(L"text"));
+
+ auto params2 = params;
+ params2.erase(params2.begin());
- text_width.set(500);
- panel_height.set(50);
+ scene->call(params2);
return scene;
}
layer(const std::wstring& name, const spl::shared_ptr<frame_producer>& producer);
};
+struct keyframe
+{
+ std::function<void ()> on_start_animate;
+ std::function<void (int64_t start_frame, int64_t current_frame)> on_animate_to;
+ std::function<void ()> on_destination_frame;
+ int64_t destination_frame;
+public:
+ keyframe(int64_t destination_frame)
+ : destination_frame(destination_frame)
+ {
+ }
+};
+
template<typename T> class parameter_holder;
class parameter_holder_base
return param->value();
}
+
+ template<typename T>
+ void add_keyframe(
+ binding<T>& to_affect,
+ T destination_value,
+ int64_t at_frame,
+ const std::wstring& easing)
+ {
+ add_keyframe(to_affect, binding<T>(destination_value), at_frame, easing);
+ }
+
+ template<typename T>
+ void add_keyframe(
+ binding<T>& to_affect,
+ const binding<T>& destination_value,
+ int64_t at_frame,
+ const std::wstring& easing)
+ {
+ tweener tween(easing);
+ keyframe k(at_frame);
+
+ std::shared_ptr<T> start_value(new T);
+
+ k.on_start_animate = [=]() mutable
+ {
+ *start_value = to_affect.get();
+ to_affect.unbind();
+ };
+
+ k.on_destination_frame = [=]() mutable
+ {
+ to_affect.bind(destination_value);
+ };
+
+ k.on_animate_to =
+ [=](int64_t start_frame, int64_t current_frame) mutable
+ {
+ auto relative_frame = current_frame - start_frame;
+ auto duration = at_frame - start_frame;
+ auto tweened = static_cast<T>(tween(
+ static_cast<double>(relative_frame),
+ *start_value,
+ destination_value.get() - *start_value,
+ static_cast<double>(duration)));
+
+ to_affect.set(tweened);
+
+ CASPAR_LOG(info) << relative_frame << L" " << *start_value << L" " << duration << L" " << tweened;
+ };
+
+ store_keyframe(to_affect.identity(), k);
+ }
+
+ template<typename T>
+ void add_keyframe(binding<T>& to_affect, T set_value, int64_t at_frame)
+ {
+ add_keyframe(to_affect, binding<T>(set_value), at_frame);
+ }
+
+ template<typename T>
+ void add_keyframe(binding<T>& to_affect, const binding<T>& set_value, int64_t at_frame)
+ {
+ keyframe k(at_frame);
+
+ k.on_destination_frame = [=]() mutable
+ {
+ to_affect.bind(set_value);
+ };
+
+ store_keyframe(to_affect.identity(), k);
+ }
private:
void store_parameter(
const std::wstring& name,
const std::shared_ptr<parameter_holder_base>& param);
+ void store_keyframe(void* timeline_identity, const keyframe& k);
struct impl;
std::unique_ptr<impl> impl_;