X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=core%2Fproducer%2Fscene%2Fscene_producer.cpp;h=b6339e85af612f96f52ec2967cea141b074a1404;hb=ceffb3558efafb706af50c04b4b150250e2963f0;hp=68565df8d58dbc85c42ae3877b8757e9d52642a9;hpb=b0a6986ce56a18a56e67be266d6d253af7cdcbb5;p=casparcg diff --git a/core/producer/scene/scene_producer.cpp b/core/producer/scene/scene_producer.cpp index 68565df8d..b6339e85a 100644 --- a/core/producer/scene/scene_producer.cpp +++ b/core/producer/scene/scene_producer.cpp @@ -19,9 +19,11 @@ * Author: Helge Norberg, helge.norberg@svt.se */ -#include "../../stdafx.h" +#include "../../StdAfx.h" #include +#include + #include #include @@ -34,14 +36,32 @@ namespace caspar { namespace core { namespace scene { layer::layer(const std::wstring& name, const spl::shared_ptr& producer) - : name(name), producer(producer) + : name(name) + , producer(producer) + , volume(1.0) { - clipping.width.bind(producer.get()->pixel_constraints().width); - clipping.height.bind(producer.get()->pixel_constraints().height); + crop.lower_right.x.bind(producer.get()->pixel_constraints().width); + crop.lower_right.y.bind(producer.get()->pixel_constraints().height); + perspective.upper_right.x.bind(producer.get()->pixel_constraints().width); + perspective.lower_right.x.bind(producer.get()->pixel_constraints().width); + perspective.lower_right.y.bind(producer.get()->pixel_constraints().height); + perspective.lower_left.y.bind(producer.get()->pixel_constraints().height); } adjustments::adjustments() : opacity(1.0) + , contrast(1.0) + , saturation(1.0) + , brightness(1.0) +{ +} + +levels::levels() + : min_input(0.0) + , max_input(1.0) + , gamma(1.0) + , min_output(0.0) + , max_output(1.0) { } @@ -84,30 +104,100 @@ struct timeline } }; +mark_action get_mark_action(const std::wstring& name) +{ + if (name == L"start") + return mark_action::start; + else if (name == L"stop") + return mark_action::stop; + else if (name == L"jump_to") + return mark_action::jump_to; + else if (name == L"remove") + return mark_action::remove; + else + CASPAR_THROW_EXCEPTION(user_error() << msg_info(L"Invalid mark_action " + name)); +} + +struct marker +{ + mark_action action; + std::wstring label_argument; + + marker(mark_action action, const std::wstring& label_argument) + : action(action) + , label_argument(label_argument) + { + } +}; + struct scene_producer::impl { - constraints pixel_constraints_; - std::list layers_; - interaction_aggregator aggregator_; - binding frame_number_; - binding speed_; - double frame_fraction_; - std::map timelines_; - std::map> variables_; - std::vector variable_names_; - monitor::subject monitor_subject_; - - impl(int width, int height) - : pixel_constraints_(width, height) + std::wstring producer_name_; + std::wstring template_name_; + constraints pixel_constraints_; + video_format_desc format_desc_; + std::list layers_; + interaction_aggregator aggregator_; + binding frame_number_; + binding timeline_frame_number_; + binding speed_; + mutable tbb::atomic m_x_; + mutable tbb::atomic m_y_; + binding mouse_x_; + binding mouse_y_; + double frame_fraction_ = 0.0; + std::map timelines_; + std::map> variables_; + std::vector variable_names_; + std::multimap markers_by_frame_; + std::vector> task_subscriptions_; + monitor::subject monitor_subject_; + bool paused_ = true; + bool removed_ = false; + bool going_to_mark_ = false; + + impl( + std::wstring producer_name, + std::wstring template_name, + int width, + int height, + const video_format_desc& format_desc) + : producer_name_(std::move(producer_name)) + , template_name_(std::move(template_name)) + , format_desc_(format_desc) , aggregator_([=] (double x, double y) { return collission_detect(x, y); }) - , frame_fraction_(0) { auto speed_variable = std::make_shared>(L"1.0", true, 1.0); store_variable(L"scene_speed", speed_variable); speed_ = speed_variable->value(); - auto frame_variable = std::make_shared>(L"0", true, 0); + + auto frame_variable = std::make_shared>(L"-1", true, -1); store_variable(L"frame", frame_variable); frame_number_ = frame_variable->value(); + + auto fps = format_desc_.fps * format_desc_.field_count; + auto fps_variable = std::make_shared>(boost::lexical_cast(fps), false, fps); + store_variable(L"fps", fps_variable); + + auto timeline_frame_variable = std::make_shared>(L"-1", false, -1); + store_variable(L"timeline_frame", timeline_frame_variable); + timeline_frame_number_ = timeline_frame_variable->value(); + + auto mouse_x_variable = std::make_shared>(L"0", false, 0); + auto mouse_y_variable = std::make_shared>(L"0", false, 0); + store_variable(L"mouse_x", mouse_x_variable); + store_variable(L"mouse_y", mouse_y_variable); + mouse_x_ = mouse_x_variable->value(); + mouse_y_ = mouse_y_variable->value(); + m_x_ = 0; + m_y_ = 0; + + auto scene_width = std::make_shared>(boost::lexical_cast(width), false, width); + auto scene_height = std::make_shared>(boost::lexical_cast(height), false, height); + store_variable(L"scene_width", scene_width); + store_variable(L"scene_height", scene_height); + pixel_constraints_.width = scene_width->value(); + pixel_constraints_.height = scene_height->value(); } layer& create_layer( @@ -117,12 +207,27 @@ struct scene_producer::impl layer.position.x.set(x); layer.position.y.set(y); + layer.clip.lower_right.x.bind(pixel_constraints_.width); + layer.clip.lower_right.y.bind(pixel_constraints_.height); layers_.push_back(layer); return layers_.back(); } + void reverse_layers() { + layers_.reverse(); + } + + layer& get_layer(const std::wstring& name) + { + for (auto& layer : layers_) + if (layer.name.get() == name) + return layer; + + CASPAR_THROW_EXCEPTION(user_error() << msg_info(name + L" not found in scene")); + } + void store_keyframe(void* timeline_identity, const keyframe& k) { timelines_[timeline_identity].keyframes.insert(std::make_pair(k.destination_frame, k)); @@ -135,12 +240,38 @@ struct scene_producer::impl variable_names_.push_back(name); } + void add_mark(int64_t frame, mark_action action, const std::wstring& label) + { + markers_by_frame_.insert(std::make_pair(frame, marker(action, label))); + } + + void add_task(binding when, std::function task) + { + auto subscription = when.on_change([=] + { + if (when.get()) + { + try + { + task(); + } + catch (...) + { + CASPAR_LOG_CURRENT_EXCEPTION_AT_LEVEL(debug); + CASPAR_LOG(error) << print() << " Error when invoking scene task. Turn on log level debug for stacktrace."; + } + } + }); + + task_subscriptions_.push_back(std::move(subscription)); + } + core::variable& get_variable(const std::wstring& name) { auto found = variables_.find(name); if (found == variables_.end()) - CASPAR_THROW_EXCEPTION(caspar_exception() << msg_info(name + L" not found in scene")); + CASPAR_THROW_EXCEPTION(user_error() << msg_info(name + L" not found in scene")); return *found->second; } @@ -150,62 +281,207 @@ struct scene_producer::impl return variable_names_; } - binding frame() + binding timeline_frame() { - return frame_number_; + return timeline_frame_number_; } frame_transform get_transform(const layer& layer) const { frame_transform transform; - auto& pos = transform.image_transform.fill_translation; - auto& scale = transform.image_transform.fill_scale; - //auto& clip_pos = transform.image_transform.clip_translation; - //auto& clip_scale = transform.image_transform.clip_scale; + auto& anchor = transform.image_transform.anchor; + auto& pos = transform.image_transform.fill_translation; + auto& scale = transform.image_transform.fill_scale; + auto& clip_pos = transform.image_transform.clip_translation; + auto& clip_scale = transform.image_transform.clip_scale; + auto& angle = transform.image_transform.angle; + auto& crop = transform.image_transform.crop; + auto& pers = transform.image_transform.perspective; + auto& levels = transform.image_transform.levels; + + anchor[0] = layer.anchor.x.get() / layer.producer.get()->pixel_constraints().width.get(); + anchor[1] = layer.anchor.y.get() / layer.producer.get()->pixel_constraints().height.get(); + + pos[0] = layer.position.x.get() / pixel_constraints_.width.get(); + pos[1] = layer.position.y.get() / pixel_constraints_.height.get(); + scale[0] = layer.producer.get()->pixel_constraints().width.get() / pixel_constraints_.width.get(); + scale[1] = layer.producer.get()->pixel_constraints().height.get() / pixel_constraints_.height.get(); + + clip_pos[0] = layer.clip.upper_left.x.get() / pixel_constraints_.width.get(); + clip_pos[1] = layer.clip.upper_left.y.get() / pixel_constraints_.height.get(); + clip_scale[0] = layer.clip.lower_right.x.get() / pixel_constraints_.width.get() - clip_pos[0]; + clip_scale[1] = layer.clip.lower_right.y.get() / pixel_constraints_.height.get() - clip_pos[1]; + + crop.ul[0] = layer.crop.upper_left.x.get() / layer.producer.get()->pixel_constraints().width.get(); + crop.ul[1] = layer.crop.upper_left.y.get() / layer.producer.get()->pixel_constraints().height.get(); + crop.lr[0] = layer.crop.lower_right.x.get() / layer.producer.get()->pixel_constraints().width.get(); + crop.lr[1] = layer.crop.lower_right.y.get() / layer.producer.get()->pixel_constraints().height.get(); + + pers.ul[0] = layer.perspective.upper_left.x.get() / layer.producer.get()->pixel_constraints().width.get(); + pers.ul[1] = layer.perspective.upper_left.y.get() / layer.producer.get()->pixel_constraints().height.get(); + pers.ur[0] = layer.perspective.upper_right.x.get() / layer.producer.get()->pixel_constraints().width.get(); + pers.ur[1] = layer.perspective.upper_right.y.get() / layer.producer.get()->pixel_constraints().height.get(); + pers.lr[0] = layer.perspective.lower_right.x.get() / layer.producer.get()->pixel_constraints().width.get(); + pers.lr[1] = layer.perspective.lower_right.y.get() / layer.producer.get()->pixel_constraints().height.get(); + pers.ll[0] = layer.perspective.lower_left.x.get() / layer.producer.get()->pixel_constraints().width.get(); + pers.ll[1] = layer.perspective.lower_left.y.get() / layer.producer.get()->pixel_constraints().height.get(); + + static const double PI = 3.141592653589793; + + angle = layer.rotation.get() * PI / 180.0; + + levels.min_input = layer.levels.min_input.get(); + levels.max_input = layer.levels.max_input.get(); + levels.gamma = layer.levels.gamma.get(); + levels.min_output = layer.levels.min_output.get(); + levels.max_output = layer.levels.max_output.get(); + + transform.image_transform.opacity = layer.adjustments.opacity.get(); + transform.image_transform.contrast = layer.adjustments.contrast.get(); + transform.image_transform.saturation = layer.adjustments.saturation.get(); + transform.image_transform.brightness = layer.adjustments.brightness.get(); + transform.image_transform.is_key = layer.is_key.get(); + transform.image_transform.use_mipmap = layer.use_mipmap.get(); + transform.image_transform.blend_mode = layer.blend_mode.get(); + + transform.image_transform.chroma.enable = layer.chroma_key.enable.get(); + transform.image_transform.chroma.target_hue = layer.chroma_key.target_hue.get(); + transform.image_transform.chroma.hue_width = layer.chroma_key.hue_width.get(); + transform.image_transform.chroma.min_saturation = layer.chroma_key.min_saturation.get(); + transform.image_transform.chroma.min_brightness = layer.chroma_key.min_brightness.get(); + transform.image_transform.chroma.softness = layer.chroma_key.softness.get(); + transform.image_transform.chroma.spill_suppress = layer.chroma_key.spill_suppress.get(); + transform.image_transform.chroma.spill_suppress_saturation = layer.chroma_key.spill_suppress_saturation.get(); + + transform.audio_transform.volume = layer.volume.get(); + + // Mark as sublayer, so it will be composited separately by the mixer. + transform.image_transform.layer_depth = 1; - pos[0] = static_cast(layer.position.x.get()) / static_cast(pixel_constraints_.width.get()); - pos[1] = static_cast(layer.position.y.get()) / static_cast(pixel_constraints_.height.get()); - scale[0] = static_cast(layer.producer.get()->pixel_constraints().width.get()) - / static_cast(pixel_constraints_.width.get()); - scale[1] = static_cast(layer.producer.get()->pixel_constraints().height.get()) - / static_cast(pixel_constraints_.height.get()); + return transform; + } - /*clip_pos[0] = static_cast(layer.clipping.upper_left.x.get()) / static_cast(pixel_constraints_.width.get()); - clip_pos[1] = static_cast(layer.clipping.upper_left.y.get()) / static_cast(pixel_constraints_.height.get()); - clip_scale[0] = static_cast(layer.clipping.width.get()) / static_cast(pixel_constraints_.width.get()); - clip_scale[1] = static_cast(layer.clipping.height.get()) / static_cast(pixel_constraints_.height.get());*/ + boost::optional> find_first_stop_or_jump_or_remove(int64_t start_frame, int64_t end_frame) + { + auto lower = markers_by_frame_.lower_bound(start_frame); + auto upper = markers_by_frame_.upper_bound(end_frame); - transform.image_transform.opacity = layer.adjustments.opacity.get(); - transform.image_transform.is_key = layer.is_key.get(); + if (lower == markers_by_frame_.end()) + return boost::none; - return transform; + for (auto iter = lower; iter != upper; ++iter) + { + auto action = iter->second.action; + + if (action == mark_action::stop || action == mark_action::jump_to || action == mark_action::remove) + return std::make_pair(iter->first, iter->second); + } + + return boost::none; } - draw_frame render_frame() + boost::optional> find_first_start(int64_t start_frame) { - BOOST_FOREACH(auto& timeline, timelines_) - timeline.second.on_frame(frame_number_.get()); + auto lower = markers_by_frame_.lower_bound(start_frame); - std::vector frames; + if (lower == markers_by_frame_.end()) + return boost::none; - BOOST_FOREACH(auto& layer, layers_) + for (auto iter = lower; iter != markers_by_frame_.end(); ++iter) { - if (layer.hidden.get()) - continue; + auto action = iter->second.action; - draw_frame frame(layer.producer.get()->receive()); - frame.transform() = get_transform(layer);; - frames.push_back(frame); + if (action == mark_action::start) + return std::make_pair(iter->first, iter->second); + } + + return boost::none; + } + + draw_frame render_frame() + { + if (format_desc_.field_count == 1) + return render_progressive_frame(); + else + { + prec_timer timer; + timer.tick_millis(0); + + auto field1 = render_progressive_frame(); + + timer.tick(0.5 / format_desc_.fps); + + auto field2 = render_progressive_frame(); + + return draw_frame::interlace(field1, field2, format_desc_.field_mode); } + } + void advance() + { frame_fraction_ += speed_.get(); if (std::abs(frame_fraction_) >= 1.0) { int64_t delta = static_cast(frame_fraction_); - frame_number_.set(frame_number_.get() + delta); - frame_fraction_ -= delta; + auto previous_frame = timeline_frame_number_.get(); + auto next_frame = timeline_frame_number_.get() + delta; + auto marker = find_first_stop_or_jump_or_remove(previous_frame + 1, next_frame); + + if (marker && marker->second.action == mark_action::remove) + { + remove(); + } + if (marker && !going_to_mark_) + { + if (marker->second.action == mark_action::stop) + { + timeline_frame_number_.set(marker->first); + frame_fraction_ = 0.0; + paused_ = true; + } + else if (marker->second.action == mark_action::jump_to) + { + go_to_marker(marker->second.label_argument, 0); + } + } + else + { + timeline_frame_number_.set(next_frame); + frame_fraction_ -= delta; + } + + going_to_mark_ = false; + } + } + + draw_frame render_progressive_frame() + { + if (removed_) + return draw_frame::empty(); + + mouse_x_.set(m_x_); + mouse_y_.set(m_y_); + + if (!paused_) + advance(); + + frame_number_.set(frame_number_.get() + speed_.get()); + + for (auto& timeline : timelines_) + timeline.second.on_frame(timeline_frame_number_.get()); + + std::vector frames; + + for (auto& layer : layers_) + { + if (layer.hidden.get()) + continue; + + draw_frame frame(layer.producer.get()->receive()); + frame.transform() = get_transform(layer); + frames.push_back(frame); } return draw_frame(frames); @@ -218,12 +494,15 @@ struct scene_producer::impl bool collides(double x, double y) const { - return collission_detect(x, y); + m_x_ = static_cast(x * pixel_constraints_.width.get()); + m_y_ = static_cast(y * pixel_constraints_.height.get()); + + return static_cast((collission_detect(x, y))); } boost::optional collission_detect(double x, double y) const { - BOOST_FOREACH(auto& layer, layers_ | boost::adaptors::reversed) + for (auto& layer : layers_ | boost::adaptors::reversed) { if (layer.hidden.get()) continue; @@ -237,40 +516,147 @@ struct scene_producer::impl && translated.second <= 1.0 && layer.producer.get()->collides(translated.first, translated.second)) { - return std::make_pair(transform, layer.producer.get().get()); + return std::make_pair(transform, static_cast(layer.producer.get().get())); } } return boost::optional(); } - boost::unique_future call(const std::vector& params) + std::future call(const std::vector& params) + { + if (!params.empty() && boost::ends_with(params.at(0), L"()")) + return make_ready_future(handle_call(params)); + else + return make_ready_future(handle_variable_set(params)); + } + + std::wstring handle_variable_set(const std::vector& params) { for (int i = 0; i + 1 < params.size(); i += 2) { - auto found = variables_.find(boost::to_lower_copy(params[i])); + auto found = variables_.find(boost::to_lower_copy(params.at(i))); if (found != variables_.end() && found->second->is_public()) - found->second->from_string(params[i + 1]); + found->second->from_string(params.at(i + 1)); + } + + return L""; + } + + std::wstring handle_call(const std::vector& params) + { + auto call = params.at(0); + + if (call == L"play()") + go_to_marker(params.at(1), -1); + else if (call == L"remove()") + remove(); + else if (call == L"next()") + next(); + else + CASPAR_THROW_EXCEPTION(user_error() << msg_info(L"Unknown call " + call)); + + return L""; + } + + void remove() + { + removed_ = true; + layers_.clear(); + } + + void next() + { + auto marker = find_first_start(timeline_frame_number_.get() + 1); + + if (marker) + { + timeline_frame_number_.set(marker->first - 1); + frame_fraction_ = 0.0; + paused_ = false; + going_to_mark_ = true; + } + else + { + remove(); + } + } + + void go_to_marker(const std::wstring& marker_name, int64_t offset) + { + for (auto& marker : markers_by_frame_) + { + if (marker.second.label_argument == marker_name && marker.second.action == mark_action::start) + { + timeline_frame_number_.set(marker.first + offset); + frame_fraction_ = 0.0; + paused_ = false; + going_to_mark_ = true; + + return; + } } - return wrap_as_future(std::wstring(L"")); + if (marker_name == L"intro") + { + timeline_frame_number_.set(offset); + frame_fraction_ = 0.0; + paused_ = false; + going_to_mark_ = true; + } + else if (marker_name == L"outro") + { + remove(); + } + else + CASPAR_LOG(info) << print() << L" no marker called " << marker_name << " found"; } std::wstring print() const { - return L"scene[]"; + return L"scene[type=" + name() + L" template=" + template_name_ + L"]"; } std::wstring name() const { - return L"scene"; + return producer_name_; } - + boost::property_tree::wptree info() const { boost::property_tree::wptree info; info.add(L"type", L"scene"); + info.add(L"producer-name", name()); + info.add(L"template-name", template_name_); + info.add(L"frame-number", frame_number_.get()); + info.add(L"timeline-frame-number", timeline_frame_number_.get()); + + for (auto& var : variables_) + { + boost::property_tree::wptree variable_info; + + variable_info.add(L"name", var.first); + variable_info.add(L"public", var.second->is_public()); + variable_info.add(L"value", var.second->to_string()); + + info.add_child(L"variables.variable", variable_info); + } + + for (auto& layer : layers_) + { + boost::property_tree::wptree layer_info; + + layer_info.add(L"name", layer.name.get()); + layer_info.add_child(L"producer", layer.producer.get()->info()); + layer_info.add(L"x", layer.position.x.get()); + layer_info.add(L"y", layer.position.y.get()); + layer_info.add(L"width", layer.producer.get()->pixel_constraints().width.get()); + layer_info.add(L"height", layer.producer.get()->pixel_constraints().height.get()); + + info.add_child(L"layers.layer", layer_info); + } + return info; } @@ -280,8 +666,8 @@ struct scene_producer::impl } }; -scene_producer::scene_producer(int width, int height) - : impl_(new impl(width, height)) +scene_producer::scene_producer(std::wstring producer_name, std::wstring template_name, int width, int height, const video_format_desc& format_desc) + : impl_(new impl(std::move(producer_name), std::move(template_name), width, height, format_desc)) { } @@ -301,9 +687,19 @@ layer& scene_producer::create_layer( return impl_->create_layer(producer, 0, 0, name); } -binding scene_producer::frame() +void scene_producer::reverse_layers() +{ + impl_->reverse_layers(); +} + +layer& scene_producer::get_layer(const std::wstring& name) +{ + return impl_->get_layer(name); +} + +binding scene_producer::timeline_frame() { - return impl_->frame(); + return impl_->timeline_frame(); } draw_frame scene_producer::receive_impl() @@ -338,7 +734,7 @@ boost::property_tree::wptree scene_producer::info() const return impl_->info(); } -boost::unique_future scene_producer::call(const std::vector& params) +std::future scene_producer::call(const std::vector& params) { return impl_->call(params); } @@ -359,130 +755,24 @@ void scene_producer::store_variable( impl_->store_variable(name, var); } -core::variable& scene_producer::get_variable(const std::wstring& name) +void scene_producer::add_mark(int64_t frame, mark_action action, const std::wstring& label) { - return impl_->get_variable(name); + impl_->add_mark(frame, action, label); } -const std::vector& scene_producer::get_variables() const +void scene_producer::add_task(binding when, std::function task) { - return impl_->get_variables(); + impl_->add_task(std::move(when), std::move(task)); } -spl::shared_ptr create_dummy_scene_producer(const spl::shared_ptr& frame_factory, const video_format_desc& format_desc, const std::vector& params) +core::variable& scene_producer::get_variable(const std::wstring& name) { - if (params.size() < 1 || !boost::iequals(params.at(0), L"[SCENE]")) - return core::frame_producer::empty(); - - auto scene = spl::make_shared(format_desc.width, format_desc.height); - - 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 padding(1); - binding panel_width = padding + text_width + padding; - binding panel_height = padding + text_area->pixel_constraints().height + padding; - - auto subscription = panel_width.on_change([&] - { - CASPAR_LOG(info) << "Panel width: " << panel_width.get(); - }); - - padding.set(2); + return impl_->get_variable(name); +} - auto create_param = [](std::wstring elem) -> std::vector - { - std::vector result; - result.push_back(elem); - return result; - }; - - auto& car_layer = scene->create_layer(create_producer(frame_factory, format_desc, create_param(L"car")), L"car"); - car_layer.clipping.upper_left.x.set(80); - car_layer.clipping.upper_left.y.set(45); - car_layer.clipping.width.unbind(); - car_layer.clipping.width.set(640); - car_layer.clipping.height.unbind(); - car_layer.clipping.height.set(360); - car_layer.adjustments.opacity.set(0.5); - //car_layer.hidden = scene->frame() % 50 > 25 || !(scene->frame() < 1000); - std::vector sub_params; - sub_params.push_back(L"[FREEHAND]"); - sub_params.push_back(L"640"); - sub_params.push_back(L"360"); - scene->create_layer(create_producer(frame_factory, format_desc, sub_params), 10, 10, L"freehand"); - sub_params.clear(); - - auto& color_layer = scene->create_layer(create_producer(frame_factory, format_desc, create_param(L"RED")), 110, 10, L"color"); - color_layer.producer.get()->pixel_constraints().width.set(1000); - color_layer.producer.get()->pixel_constraints().height.set(550); - - //scene->create_layer(create_producer(frame_factory, format_desc, create_param(L"SP")), 50, 50); - - auto& upper_left = scene->create_layer(create_producer(frame_factory, format_desc, create_param(L"scene/upper_left")), L"upper_left"); - auto& upper_right = scene->create_layer(create_producer(frame_factory, format_desc, create_param(L"scene/upper_right")), L"upper_right"); - auto& lower_left = scene->create_layer(create_producer(frame_factory, format_desc, create_param(L"scene/lower_left")), L"lower_left"); - auto& lower_right = scene->create_layer(create_producer(frame_factory, format_desc, create_param(L"scene/lower_right")), L"lower_right"); - auto& text_layer = scene->create_layer(text_area, L"text_area"); - upper_left.adjustments.opacity.bind(text_layer.adjustments.opacity); - upper_right.adjustments.opacity.bind(text_layer.adjustments.opacity); - lower_left.adjustments.opacity.bind(text_layer.adjustments.opacity); - lower_right.adjustments.opacity.bind(text_layer.adjustments.opacity); - - /* - binding panel_x = (scene->frame() - .as() - .transformed([](double v) { return std::sin(v / 20.0); }) - * 20.0 - + 40.0) - .transformed([](double v) { return std::floor(v); }); // snap to pixels instead of subpixels - */ - tweener tween(L"easeoutbounce"); - binding 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 panel_x = when(scene->frame() < 50) - .then(scene->frame().as().transformed([tween](double t) { return tween(t, 0.0, 200, 50); })) - .otherwise(200.0);*/ - //binding panel_y = when(car_layer.hidden).then(500.0).otherwise(-panel_x + 300); - binding 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"); - - scene->add_keyframe(text_layer.adjustments.opacity, 1.0, 100); - scene->add_keyframe(text_layer.adjustments.opacity, 0.0, 125, L"linear"); - scene->add_keyframe(text_layer.adjustments.opacity, 1.0, 150, L"linear"); - - 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; - upper_right.position.y = upper_left.position.y; - lower_left.position.x = upper_left.position.x; - 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(); - - text_area->text().bind(scene->create_variable(L"text", true)); - - auto params2 = params; - params2.erase(params2.begin()); - - scene->call(params2); - - return scene; +const std::vector& scene_producer::get_variables() const +{ + return impl_->get_variables(); } }}}