diff --git a/CloneSource.cpp b/CloneSource.cpp
index 963aafa..eae8d2a 100644
--- a/CloneSource.cpp
+++ b/CloneSource.cpp
@@ -17,38 +17,53 @@
* along with this program. If not, see .
**/
+#include
+
#include
+#include
#include "Log.h"
#include "Resource.h"
#include "Visitor.h"
+#include "FrameBuffer.h"
#include "Decorations.h"
#include "CloneSource.h"
-CloneSource *Source::clone(uint64_t id)
-{
- CloneSource *s = new CloneSource(this, id);
-
- clones_.push_back(s);
-
- return s;
-}
-
-
-CloneSource::CloneSource(Source *origin, uint64_t id) : Source(id), origin_(origin)
+
+CloneSource::CloneSource(Source *origin, uint64_t id) : Source(id), origin_(origin), cloningsurface_(nullptr),
+ read_index_(0), write_index_(0), delay_(0.0), paused_(false), image_mode_(CLONE_TEXTURE)
{
+ // initial name copies the origin name: diplucates are namanged in session
name_ = origin->name();
+
// set symbol
symbol_ = new Symbol(Symbol::CLONE, glm::vec3(0.75f, 0.75f, 0.01f));
symbol_->scale_.y = 1.5f;
+
+ // init array
+ stack_.fill(nullptr);
+ timestamp_.fill(0.0);
+
+ timer_ = g_timer_new ();
}
CloneSource::~CloneSource()
{
if (origin_)
origin_->clones_.remove(this);
+
+ // delete all frame buffers
+ for (size_t i = 0; i < stack_.size(); ++i){
+ if ( stack_[i] != nullptr )
+ delete stack_[i];
+ }
+
+ if (cloningsurface_)
+ delete cloningsurface_;
+
+ g_free(timer_);
}
CloneSource *CloneSource::clone(uint64_t id)
@@ -64,15 +79,29 @@ void CloneSource::init()
{
if (origin_ && origin_->mode_ > Source::UNINITIALIZED) {
- // get the texture index from framebuffer of view, apply it to the surface
- texturesurface_->setTextureIndex( origin_->texture() );
+ // create frame buffers where to copy frames of the origin source
+ glm::vec3 res = origin_->frame()->resolution();
+ for (size_t i = 0; i < stack_.size(); ++i){
+ stack_[i] = new FrameBuffer( res, origin_->frame()->use_alpha() );
+ }
- // create Frame buffer matching size of session
- FrameBuffer *renderbuffer = new FrameBuffer( origin_->frame()->resolution(), true);
+ g_timer_start(timer_);
+
+ cloningsurface_ = new Surface;
+ cloningsurface_->setTextureIndex( origin()->texture() );
+
+ // set initial texture surface
+ texturesurface_->setTextureIndex( stack_[read_index_]->texture() );
+
+ // create Frame buffer matching size of images
+ FrameBuffer *renderbuffer = new FrameBuffer( res, true);
// set the renderbuffer of the source and attach rendering nodes
attach(renderbuffer);
+ // force update of activation mode
+ active_ = true;
+
// deep update to reorder
++View::need_deep_update_;
@@ -83,6 +112,9 @@ void CloneSource::init()
void CloneSource::setActive (bool on)
{
+ // request update
+ need_update_ |= active_ != on;
+
active_ = on;
groups_[View::RENDERING]->visible_ = active_;
@@ -98,17 +130,90 @@ void CloneSource::setActive (bool on)
if (active_)
activesurface_->setTextureIndex(Resource::getTextureTransparent());
else
- activesurface_->setTextureIndex(origin_->texture());
+ activesurface_->setTextureIndex(stack_[read_index_]->texture());
}
}
}
+void CloneSource::replay()
+{
+ read_index_ = (write_index_ + 1 )%(stack_.size());
+}
+
+void CloneSource::update(float dt)
+{
+ if (active_ && !paused_ && cloningsurface_ != nullptr) {
+
+ double now = g_timer_elapsed (timer_, NULL) ;
+
+ // increment enplacement of write index
+ write_index_ = (write_index_+1)%(stack_.size());
+ timestamp_[write_index_] = now;
+
+ // CLONE_RENDER : blit rendered framebuffer in the stack
+ if (image_mode_ == CLONE_RENDER)
+ origin_->frame()->blit(stack_[write_index_]);
+ // CLONE_TEXTURE : render origin texture in the stack
+ else {
+ stack_[write_index_]->begin();
+ cloningsurface_->draw(glm::identity(), stack_[write_index_]->projection());
+ stack_[write_index_]->end();
+ }
+
+ // define emplacement of read index
+ if (delay_ < 0.001)
+ // minimal difference if no delay
+ read_index_ = write_index_;
+ else
+ {
+ // starting where we are at, get the next index that satisfies the delay
+ size_t previous_index = read_index_;
+ while ( now - timestamp_[read_index_] > delay_) {
+ // usually, one frame increment suffice
+ read_index_ = (read_index_ + 1 )%(stack_.size());
+ // break the loop if running infinite (never happens)
+ if (previous_index == read_index_)
+ break;
+ }
+ }
+
+ // update the source surface to be rendered
+ texturesurface_->setTextureIndex( stack_[read_index_]->texture() );
+
+ }
+
+ Source::update(dt);
+}
+
+
+void CloneSource::setDelay(double second)
+{
+ delay_ = CLAMP(second, 0.0, 1.0);
+}
+
+void CloneSource::play (bool on)
+{
+ // if a different state is asked
+ if (paused_ == on) {
+
+ // restart clean if was paused
+ if (paused_) {
+ g_timer_reset(timer_);
+ timestamp_.fill(0.0);
+ write_index_ = 0;
+ read_index_ = 1;
+ }
+ // toggle state
+ paused_ = !on;
+ }
+}
+
uint CloneSource::texture() const
{
- if (origin_ != nullptr)
- return origin_->texture();
+ if (cloningsurface_ != nullptr)
+ return stack_[read_index_]->texture();
else
- return Resource::getTextureBlack();
+ return Resource::getTextureTransparent();
}
void CloneSource::accept(Visitor& v)
diff --git a/CloneSource.h b/CloneSource.h
index 4ee4c8a..0e6e7a2 100644
--- a/CloneSource.h
+++ b/CloneSource.h
@@ -1,6 +1,10 @@
#ifndef CLONESOURCE_H
#define CLONESOURCE_H
+#include
+
+#define DELAY_ARRAY_SIZE 70
+
#include "Source.h"
class CloneSource : public Source
@@ -11,11 +15,12 @@ public:
~CloneSource();
// implementation of source API
+ void update (float dt) override;
void setActive (bool on) override;
- bool playing () const override { return true; }
- void play (bool) override {}
- bool playable () const override { return false; }
- void replay () override {}
+ bool playing () const override { return !paused_; }
+ void play (bool on) override;
+ bool playable () const override { return true; }
+ void replay () override;
uint texture() const override;
bool failed() const override { return origin_ == nullptr; }
void accept (Visitor& v) override;
@@ -24,6 +29,17 @@ public:
inline void detach() { origin_ = nullptr; }
inline Source *origin() const { return origin_; }
+ typedef enum {
+ CLONE_TEXTURE = 0,
+ CLONE_RENDER
+ } CloneImageMode;
+
+ void setImageMode(CloneImageMode m) { image_mode_ = m; }
+ CloneImageMode imageMode() const { return image_mode_; }
+
+ void setDelay(double second);
+ double delay() const { return delay_; }
+
glm::ivec2 icon() const override;
std::string info() const override;
@@ -33,6 +49,19 @@ protected:
void init() override;
Source *origin_;
+
+ // cloning
+ std::array stack_;
+ Surface *cloningsurface_;
+ size_t read_index_, write_index_;
+
+ GTimer *timer_;
+ std::array timestamp_;
+ double delay_;
+
+ // control
+ bool paused_;
+ CloneImageMode image_mode_;
};
diff --git a/ImGuiVisitor.cpp b/ImGuiVisitor.cpp
index 4c2ca27..df87fc6 100644
--- a/ImGuiVisitor.cpp
+++ b/ImGuiVisitor.cpp
@@ -714,6 +714,20 @@ void ImGuiVisitor::visit (CloneSource& s)
Mixer::manager().setCurrentSource(s.origin());
ImGui::SameLine();
ImGui::Text("Source");
+
+ ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
+ int m = (int) s.imageMode();
+ if (ImGui::Combo("Image", &m, "Original\0Post-processed\0") )
+ s.setImageMode((CloneSource::CloneImageMode)m);
+
+
+ ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
+ float d = s.delay();
+// if (ImGui::SliderFloat("Delay", &d, 0.f, 1.f, "%.2f s")){
+ if (ImGui::SliderFloat("Delay", &d, 0.f, 1.f, d < 0.01f ? "None" : "%.2f s")){
+ s.setDelay(d);
+ }
+
}
void ImGuiVisitor::visit (PatternSource& s)
diff --git a/InfoVisitor.cpp b/InfoVisitor.cpp
index 02139e6..6b030b0 100644
--- a/InfoVisitor.cpp
+++ b/InfoVisitor.cpp
@@ -178,10 +178,18 @@ void InfoVisitor::visit (RenderSource& s)
void InfoVisitor::visit (CloneSource& s)
{
- if (current_id_ == s.id())
+ if (current_id_ == s.id() || s.origin() == nullptr)
return;
- information_ = "Clone of " + s.origin()->name();
+ std::ostringstream oss;
+ oss << "Clone of '" << s.origin()->name() << "' " << std::endl;
+
+ if (s.frame()){
+ oss << s.frame()->width() << " x " << s.frame()->height() << ", ";
+ oss << "RGBA";
+ }
+
+ information_ = oss.str();
current_id_ = s.id();
}
diff --git a/SessionCreator.cpp b/SessionCreator.cpp
index a89fd64..87ec47a 100644
--- a/SessionCreator.cpp
+++ b/SessionCreator.cpp
@@ -407,7 +407,7 @@ void SessionLoader::load(XMLElement *sessionNode)
// found the orign source
if (origin != session_->end()) {
// create a new source of type Clone
- Source *clone_source = (*origin)->clone(id_xml_);
+ CloneSource *clone_source = (*origin)->clone(id_xml_);
// add source to session
session_->addSource(clone_source);
@@ -1082,3 +1082,16 @@ void SessionLoader::visit (GenericStreamSource& s)
}
}
+
+void SessionLoader::visit (CloneSource& s)
+{
+ // set attributes
+ int imagemode = 0;
+ xmlCurrent_->QueryIntAttribute("imageMode", &imagemode);
+ s.setImageMode((CloneSource::CloneImageMode)imagemode);
+
+ double delay = 0.0;
+ xmlCurrent_->QueryDoubleAttribute("delay", &delay);
+ s.setDelay(delay);
+}
+
diff --git a/SessionCreator.h b/SessionCreator.h
index f2cb582..e223e49 100644
--- a/SessionCreator.h
+++ b/SessionCreator.h
@@ -55,6 +55,7 @@ public:
void visit (SessionFileSource& s) override;
void visit (SessionGroupSource& s) override;
void visit (RenderSource& s) override;
+ void visit (CloneSource& s) override;
void visit (PatternSource& s) override;
void visit (DeviceSource& s) override;
void visit (NetworkSource& s) override;
diff --git a/SessionVisitor.cpp b/SessionVisitor.cpp
index 3eab5c2..10a309c 100644
--- a/SessionVisitor.cpp
+++ b/SessionVisitor.cpp
@@ -634,12 +634,16 @@ void SessionVisitor::visit (RenderSource&)
void SessionVisitor::visit (CloneSource& s)
{
xmlCurrent_->SetAttribute("type", "CloneSource");
+ xmlCurrent_->SetAttribute("imageMode", (int) s.imageMode());
+ xmlCurrent_->SetAttribute("delay", (double) s.delay());
XMLElement *origin = xmlDoc_->NewElement("origin");
origin->SetAttribute("id", s.origin()->id());
+
xmlCurrent_->InsertEndChild(origin);
XMLText *text = xmlDoc_->NewText( s.origin()->name().c_str() );
origin->InsertEndChild( text );
+
}
void SessionVisitor::visit (PatternSource& s)
diff --git a/Source.cpp b/Source.cpp
index 0cfc40c..d9790d9 100644
--- a/Source.cpp
+++ b/Source.cpp
@@ -649,6 +649,17 @@ void Source::call(SourceCallback *callback, bool override)
}
}
+
+CloneSource *Source::clone(uint64_t id)
+{
+ CloneSource *s = new CloneSource(this, id);
+
+ clones_.push_back(s);
+
+ return s;
+}
+
+
void Source::update(float dt)
{
// keep delta-t