From cf72a4d6580c44e9998ae3825a409a1dd7d9025a Mon Sep 17 00:00:00 2001 From: brunoherbelin Date: Sat, 4 Apr 2020 23:47:06 +0200 Subject: [PATCH] New visitor for ImGui display of scene --- CMakeLists.txt | 1 + ImGuiVisitor.cpp | 129 ++++++++++++++++++++++++++ ImGuiVisitor.h | 22 ++++- Scene.cpp | 11 ++- Scene.h | 11 ++- main.cpp | 230 +++++++++++++---------------------------------- snippets.cpp | 218 ++++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 448 insertions(+), 174 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5bf96cd..eb786cd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -228,6 +228,7 @@ set(VMIX_SRCS RenderingManager.cpp UserInterfaceManager.cpp ImGuiToolkit.cpp + ImGuiVisitor.cpp GstToolkit.cpp tinyxml2Toolkit.cpp ) diff --git a/ImGuiVisitor.cpp b/ImGuiVisitor.cpp index 25de8d9..88e077b 100644 --- a/ImGuiVisitor.cpp +++ b/ImGuiVisitor.cpp @@ -1,6 +1,135 @@ #include "ImGuiVisitor.h" +#include +#include +#include +#include +#include +#include + +#include "Log.h" +#include "Scene.h" +#include "Primitives.h" +#include "ImageShader.h" +#include "MediaPlayer.h" + +#include "imgui.h" +#include "ImGuiToolkit.h" + ImGuiVisitor::ImGuiVisitor() { } + +void ImGuiVisitor::visit(Node &n) +{ + +} + +void ImGuiVisitor::visit(Group &n) +{ + std::string id = std::to_string(n.id()); + if (ImGui::TreeNode(id.c_str(), "Group")) + { + + // n.transform_ + // MODEL VIEW + float translation[2] = { n.transform_[3][0], n.transform_[3][1]}; + if (ImGuiToolkit::ButtonIcon(6, 15)) { + translation[0] = 0.f; + translation[1] = 0.f; + } + ImGui::SameLine(0, 10); + ImGui::SliderFloat2("position", translation, -5.0, 5.0); + + float rotation = asin(n.transform_[0][1]); + if (ImGuiToolkit::ButtonIcon(4, 15)) rotation = 0.f; + ImGui::SameLine(0, 10); + ImGui::SliderFloat("rotation", &rotation, 0, glm::two_pi()); + + float scale = n.transform_[2][2]; + if (ImGuiToolkit::ButtonIcon(3, 15)) scale = 1.f; + ImGui::SameLine(0, 10); + ImGui::SliderFloat("scale", &scale, 0.1f, 10.f, "%.3f", 3.f); + + glm::mat4 View = glm::translate(glm::identity(), glm::vec3(translation[0], translation[1], 0.f)); + View = glm::rotate(View, rotation, glm::vec3(0.0f, 0.0f, 1.0f)); + glm::mat4 Model = glm::scale(glm::identity(), glm::vec3(scale, scale, scale)); + n.transform_ = View * Model; + + // loop over members of a group + for (int i = 0; i < n.numChildren(); ++i) + { + n.getChild(i)->accept(*this); + } + + ImGui::TreePop(); + } +} + +void ImGuiVisitor::visit(Switch &n) +{ + +} + +void ImGuiVisitor::visit(Primitive &n) +{ + ImGui::PushID(n.id()); + ImGui::Text("Primitive"); + + + n.getShader()->accept(*this); + ImGui::PopID(); +} + +void ImGuiVisitor::visit(ImageSurface &n) +{ + +} + +void ImGuiVisitor::visit(MediaSurface &n) +{ + ImGui::Text("%s", n.getFilename().c_str()); + n.getMediaPlayer()->accept(*this); +} + +void ImGuiVisitor::visit(MediaPlayer &n) +{ + + ImGui::Text("Media Player"); +} + +void ImGuiVisitor::visit(Shader &n) +{ + ImGui::ColorEdit3("color", glm::value_ptr(n.color) ) ; +} + +void ImGuiVisitor::visit(ImageShader &n) +{ +} + +void ImGuiVisitor::visit(LineStrip &n) +{ + ImGui::Text("Lines"); +} + +void ImGuiVisitor::visit(LineSquare &n) +{ + ImGui::Text("Square"); +} + +void ImGuiVisitor::visit(LineCircle &n) +{ + ImGui::Text("Circle"); +} + +void ImGuiVisitor::visit(Scene &n) +{ + ImGui::SetNextItemOpen(true, ImGuiCond_Once); + if (ImGui::CollapsingHeader("Scene Property Tree")) + { + n.getRoot()->accept(*this); + } +} + + diff --git a/ImGuiVisitor.h b/ImGuiVisitor.h index 8e72ca0..4160d79 100644 --- a/ImGuiVisitor.h +++ b/ImGuiVisitor.h @@ -1,11 +1,29 @@ #ifndef IMGUIVISITOR_H #define IMGUIVISITOR_H +#include "Visitor.h" -class ImGuiVisitor +class ImGuiVisitor: public Visitor { public: ImGuiVisitor(); + + // Elements of Scene + void visit(Scene& n) override; + void visit(Node& n) override; + void visit(Group& n) override; + void visit(Switch& n) override; + void visit(Primitive& n) override; + void visit(ImageSurface& n) override; + void visit(MediaSurface& n) override; + void visit(LineStrip& n) override; + void visit(LineSquare& n) override; + void visit(LineCircle& n) override; + + // Elements with attributes + void visit(MediaPlayer& n) override; + void visit(Shader& n) override; + void visit(ImageShader& n) override; }; -#endif // IMGUIVISITOR_H \ No newline at end of file +#endif // IMGUIVISITOR_H diff --git a/Scene.cpp b/Scene.cpp index 59feb48..61420ec 100644 --- a/Scene.cpp +++ b/Scene.cpp @@ -14,9 +14,16 @@ #include #include +#include +#include + // Node -Node::Node() : parent_(nullptr), visible_(false) +Node::Node() : parent_(nullptr), visible_(false), initialized_(false) { + // create unique id + auto duration = std::chrono::system_clock::now().time_since_epoch(); + id_ = std::chrono::duration_cast(duration).count() % 100000000; + worldToLocal_ = glm::identity(); localToWorld_ = glm::identity(); transform_ = glm::identity(); @@ -101,6 +108,7 @@ void Primitive::init() if ( arrayBuffer_ ) glDeleteBuffers ( 1, &arrayBuffer_); if ( elementBuffer_ ) glDeleteBuffers ( 1, &elementBuffer_); + initialized_ = true; visible_ = true; } @@ -147,6 +155,7 @@ Group::~Group() void Group::init() { visible_ = true; + initialized_ = true; } void Group::update( float dt ) diff --git a/Scene.h b/Scene.h index 69b4496..a173a19 100644 --- a/Scene.h +++ b/Scene.h @@ -15,18 +15,21 @@ class Node { public: Node(); - virtual ~Node() {} + virtual ~Node() {} + inline int id() { return id_; } virtual void init() = 0; virtual void draw( glm::mat4 modelview, glm::mat4 projection) = 0; virtual void accept(Visitor& v); virtual void update( float dt ); - - virtual glm::mat4 getWorldToLocalMatrix() {return worldToLocal_;} - virtual glm::mat4 getLocalToWorldMatrix() {return localToWorld_;} + virtual bool initialized() { return initialized_; } + virtual glm::mat4 getWorldToLocalMatrix() { return worldToLocal_; } + virtual glm::mat4 getLocalToWorldMatrix() { return localToWorld_; } Node* parent_; bool visible_; + bool initialized_; + int id_; glm::mat4 worldToLocal_; glm::mat4 localToWorld_; glm::mat4 transform_; diff --git a/main.cpp b/main.cpp index ff3e46e..fc95f1a 100644 --- a/main.cpp +++ b/main.cpp @@ -36,127 +36,54 @@ #include "MediaPlayer.h" #include "Scene.h" #include "Primitives.h" +#include "ImGuiVisitor.h" #include "SessionVisitor.h" #define PI 3.14159265358979323846 +// test scene + +//// ("file:///home/bhbn/Videos/MOV001.MOD"); +//// ("file:///home/bhbn/Videos/TestFormats/Commodore64GameReviewMoondust.flv"); +//// ("file:///home/bhbn/Videos/fish.mp4"); +//// ("file:///home/bhbn/Videos/jean/Solitude1080p.mov"); +//// ("file:///home/bhbn/Videos/TearsOfSteel_720p_h265.mkv"); +//// ("file:///home/bhbn/Videos/TestFormats/_h264GoldenLamps.mkv"); +//// ("file:///home/bhbn/Videos/TestEncoding/vpxvp9high.webm"); +//// ("file:///home/bhbn/Videos/iss.mov"); +/// Scene scene; FrameBuffer *output; -MediaPlayer testmedia; -MediaPlayer testmedia2("testmedia2"); -ImageShader rendering_shader; -unsigned int vbo, vao, ebo; -float texturear = 1.0; -GLuint textureimagepng = 0; +MediaSurface testnode1("file:///home/bhbn/Videos/iss.mov"); +MediaSurface testnode2("file:///home/bhbn/Videos/fish.mp4"); +ImageSurface testnode3("images/v-mix_256x256.png"); -// from https://gstreamer.freedesktop.org/documentation/application-development/advanced/pipeline-manipulation.html?gi-language=c - -void drawMediaBackgound() -{ - if ( !testmedia2.isOpen() ) - return; - - // - // RENDER SOURCE - // - testmedia2.update(); - - // use the shader - rendering_shader.projection = Rendering::manager().Projection(); - rendering_shader.modelview = glm::identity();; - rendering_shader.use(); - // use the media - testmedia2.bind(); - // draw the vertex array - glBindVertexArray(vao); - glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_INT, 0); - glBindVertexArray(0); - glBindTexture(GL_TEXTURE_2D, 0); - - // - // GUI to control SOURCE - // - { - ImGui::Begin("Image properties"); - - // MODEL VIEW - static float translation[] = {0.f, 0.f}; - if (ImGuiToolkit::ButtonIcon(6, 15)) { - translation[0] = 0.f; - translation[1] = 0.f; - } - ImGui::SameLine(0, 10); - ImGui::SliderFloat2("position", translation, -5.0, 5.0); - - static float rotation = 0.f; - if (ImGuiToolkit::ButtonIcon(4, 15)) rotation = 0.f; - ImGui::SameLine(0, 10); - ImGui::SliderFloat("rotation", &rotation, 0, 2 * PI); - - static float scale = 1.f; - if (ImGuiToolkit::ButtonIcon(3, 15)) scale = 1.f; - ImGui::SameLine(0, 10); - ImGui::SliderFloat("scale", &scale, 0.1f, 10.f, "%.3f", 3.f); - - // set modelview -// rendering_shader.setModelview(translation[0], translation[1], rotation, scale, testmedia2.AspectRatio()); - - // color picker - if (ImGuiToolkit::ButtonIcon(16, 8)) rendering_shader.color = glm::vec4(1.f); - ImGui::SameLine(0, 10); - ImGui::ColorEdit3("color", glm::value_ptr(rendering_shader.color) ) ; - // brightness slider - if (ImGuiToolkit::ButtonIcon(4, 1)) rendering_shader.brightness = 0.f; - ImGui::SameLine(0, 10); - ImGui::SliderFloat("brightness", &rendering_shader.brightness, -1.0, 1.0, "%.3f", 2.f); - // contrast slider - if (ImGuiToolkit::ButtonIcon(2, 1)) rendering_shader.contrast = 0.f; - ImGui::SameLine(0, 10); - ImGui::SliderFloat("contrast", &rendering_shader.contrast, -1.0, 1.0, "%.3f", 2.f); - - ImGui::End(); - } - -} - void drawMediaPlayer() { static GstClockTime begin = GST_CLOCK_TIME_NONE; static GstClockTime end = GST_CLOCK_TIME_NONE; - if ( !testmedia.isOpen() ) + if ( !testnode2.getMediaPlayer() || !testnode2.getMediaPlayer()->isOpen() ) return; - testmedia.update(); + MediaPlayer *mp = testnode2.getMediaPlayer(); - if ( begin == GST_CLOCK_TIME_NONE) { - - begin = testmedia.duration() / 5; - end = testmedia.duration() / 3; -// if ( testmedia.addPlaySegment(begin, end) ) -// std::cerr << " - first segment " << std::endl; - -// begin *= 2; -// end *= 2; -// if ( testmedia.addPlaySegment(begin, end) ) -// std::cerr << " - second segment " << std::endl; - - } - - ImGui::Begin("Media Player"); + ImGui::SetNextWindowPos(ImVec2(200, 200), ImGuiCond_FirstUseEver); + ImGui::SetNextWindowSize(ImVec2(300, 300), ImGuiCond_FirstUseEver); + ImGui::Begin(IMGUI_TITLE_MEDIAPLAYER); float width = ImGui::GetContentRegionAvail().x; float spacing = ImGui::GetStyle().ItemInnerSpacing.x; - ImVec2 imagesize ( width, width / testmedia.aspectRatio()); - ImGui::Image((void*)(intptr_t)testmedia.texture(), imagesize); + ImVec2 imagesize ( width, width / mp->aspectRatio()); + ImGui::Image((void*)(intptr_t)mp->texture(), imagesize); if (ImGui::Button(ICON_FA_FAST_BACKWARD)) - testmedia.rewind(); + mp->rewind(); ImGui::SameLine(0, spacing); // remember playing mode of the GUI - static bool media_playing_mode = testmedia.isPlaying(); + static bool media_playing_mode = mp->isPlaying(); // display buttons Play/Stop depending on current playing mode if (media_playing_mode) { @@ -167,7 +94,7 @@ void drawMediaPlayer() ImGui::PushButtonRepeat(true); if (ImGui::Button(ICON_FA_FORWARD)) - testmedia.fastForward (); + mp->fastForward (); ImGui::PopButtonRepeat(); } else { @@ -178,7 +105,7 @@ void drawMediaPlayer() ImGui::PushButtonRepeat(true); if (ImGui::Button(ICON_FA_STEP_FORWARD)) - testmedia.seekNextFrame(); + mp->seekNextFrame(); ImGui::PopButtonRepeat(); } @@ -195,48 +122,32 @@ void drawMediaPlayer() ImGui::SameLine(0, spacing); ImGui::SetNextItemWidth(90); if ( ImGui::SliderInt("", ¤t_loop, 0, 2, current_loop_name) ) - testmedia.setLoop( (MediaPlayer::LoopMode) current_loop ); + mp->setLoop( (MediaPlayer::LoopMode) current_loop ); - float speed = static_cast(testmedia.playSpeed()); + float speed = static_cast(mp->playSpeed()); ImGui::SameLine(0, spacing); ImGui::SetNextItemWidth(270); // ImGui::SetNextItemWidth(width - 90.0); if (ImGui::SliderFloat( "Speed", &speed, -10.f, 10.f, "x %.1f", 2.f)) - testmedia.setPlaySpeed( static_cast(speed) ); + mp->setPlaySpeed( static_cast(speed) ); ImGui::SameLine(0, spacing); if (ImGuiToolkit::ButtonIcon(19, 15)) { speed = 1.f; - testmedia.setPlaySpeed( static_cast(speed) ); + mp->setPlaySpeed( static_cast(speed) ); } - guint64 current_t = testmedia.position(); + guint64 current_t = mp->position(); guint64 seek_t = current_t; bool slider_pressed = ImGuiToolkit::TimelineSlider( "simpletimeline", &seek_t, - testmedia.duration(), testmedia.frameDuration()); - -// std::list > segments = testmedia.getPlaySegments(); -// bool slider_pressed = ImGuiToolkit::TimelineSliderEdit( "timeline", &seek_t, testmedia.Duration(), -// testmedia.FrameDuration(), segments); - -// if (!segments.empty()) { -// // segments have been modified -// g_print("Segments modified \n"); - -// for (std::list< std::pair >::iterator s = segments.begin(); s != segments.end(); s++){ -// MediaSegment newsegment(s->first, s->second); -// testmedia.removeAllPlaySegmentOverlap(newsegment); -// if (!testmedia.addPlaySegment(newsegment)) -// g_print("new Segment could not be added \n"); -// } -// } + mp->duration(), mp->frameDuration()); // if the seek target time is different from the current position time // (i.e. the difference is less than one frame) - if ( ABS_DIFF (current_t, seek_t) > testmedia.frameDuration() ) { + if ( ABS_DIFF (current_t, seek_t) > mp->frameDuration() ) { // request seek (ASYNC) - testmedia.seekTo(seek_t); + mp->seekTo(seek_t); } // play/stop command should be following the playing mode (buttons) @@ -246,13 +157,13 @@ void drawMediaPlayer() // apply play action to media only if status should change // NB: The seek command performed an ASYNC state change, but // gst_element_get_state called in isPlaying() will wait for the state change to complete. - if ( testmedia.isPlaying() != media_play ) { - testmedia.play( media_play ); + if ( mp->isPlaying() != media_play ) { + mp->play( media_play ); } // display info - ImGui::Text("%s %d x %d", testmedia.codec().c_str(), testmedia.width(), testmedia.height()); - ImGui::Text("Framerate %.2f / %.2f", testmedia.updateFrameRate() , testmedia.frameRate() ); + ImGui::Text("%s %d x %d", mp->codec().c_str(), mp->width(), mp->height()); + ImGui::Text("Framerate %.2f / %.2f", mp->updateFrameRate() , mp->frameRate() ); ImGui::End(); } @@ -260,24 +171,34 @@ void drawMediaPlayer() void drawScene() { + // compute dt static gint64 last_time = gst_util_get_timestamp (); gint64 current_time = gst_util_get_timestamp (); gint64 dt = current_time - last_time; + last_time = current_time; + // recursive update from root of scene glm::mat4 MV = glm::identity(); - glm::mat4 P = Rendering::manager().Projection(); + glm::mat4 P = glm::scale( glm::ortho(-5.f, 5.f, -5.f, 5.f), glm::vec3(1.f, output->aspectRatio(), 1.f)); + // glm::mat4 View = glm::translate(glm::identity(), glm::vec3(0, 0, 0.f)); // View = glm::rotate(View, 0.f, glm::vec3(0.0f, 0.0f, 1.0f)); // glm::mat4 Model = glm::scale(glm::identity(), glm::vec3(1, 1, 1)); // mv = View * Model; - scene.root_.update( static_cast( GST_TIME_AS_MSECONDS(dt)) * 0.001f ); + // draw in output frame buffer output->bind(); scene.root_.draw(MV, P); FrameBuffer::release(); - last_time = current_time; + // draw GUI tree scene + ImGui::Begin(IMGUI_TITLE_MAINWINDOW); + + static ImGuiVisitor v; + scene.accept(v); + + ImGui::End(); } @@ -285,7 +206,9 @@ void drawPreview() { if (output) { - ImGui::Begin("Preview"); + ImGui::SetNextWindowPos(ImVec2(100, 300), ImGuiCond_FirstUseEver); + ImGui::SetNextWindowSize(ImVec2(640, 480), ImGuiCond_FirstUseEver); + ImGui::Begin(ICON_FA_LAPTOP " Preview"); float width = ImGui::GetContentRegionAvail().x; ImVec2 imagesize ( width, width / output->aspectRatio()); @@ -293,6 +216,8 @@ void drawPreview() ImGui::End(); } + + } @@ -323,47 +248,16 @@ int main(int, char**) gst_debug_set_active(TRUE); #endif -//// testmedia.Open("file:///home/bhbn/Videos/MOV001.MOD"); -//// testmedia.Open("file:///home/bhbn/Videos/TestFormats/Commodore64GameReviewMoondust.flv"); -//// testmedia.Open("file:///home/bhbn/Videos/fish.mp4"); -//// testmedia.Open("file:///home/bhbn/Videos/jean/Solitude1080p.mov"); -// testmedia.Open("file:///home/bhbn/Videos/TearsOfSteel_720p_h265.mkv"); -//// testmedia.Open("file:///home/bhbn/Videos/TestFormats/_h264GoldenLamps.mkv"); -//// testmedia.Open("file:///home/bhbn/Videos/TestEncoding/vpxvp9high.webm"); -//// testmedia.Open("file:///home/bhbn/Videos/iss.mov"); -// testmedia.Play(false); - - // Add draw callbacks to the Rendering -// Rendering::manager().AddDrawCallback(drawMediaPlayer); - -//// testmedia2.Open("file:///home/bhbn/Images/Butterfly.gif"); -//// testmedia2.Open("file:///home/bhbn/Images/Scan-090614-0022.jpg"); -//// testmedia2.Open("file:///home/bhbn/Images/svg/abstract.svg"); -// testmedia2.Open("file:///home/bhbn/Videos/iss.mov"); -//// testmedia2.Open("file:///home/bhbn/Images/4k/colors-3840x2160-splash-4k-18458.jpg"); -//// testmedia2.Open("file:///home/bhbn/Videos/Upgrade.2018.720p.AMZN.WEB-DL.DDP5.1.H.264-NTG.m4v"); -// testmedia2.Play(true); -// // create our geometries -// create_square_glm(vbo, vao, ebo); -// // Add draw callbacks to the Rendering -// Rendering::manager().AddDrawCallback(drawMediaBackgound); - // test text editor // UserInterface::manager().OpenTextEditor( Resource::getText("shaders/texture-shader.fs") ); - // init the scene scene.root_.init(); - Rendering::manager().PushBackDrawCallback(drawScene); + Rendering::manager().PushFrontDrawCallback(drawScene); - // create and add a elements to the scene - MediaSurface testnode1("file:///home/bhbn/Videos/iss.mov"); + // init elements to the scene testnode1.init(); - - MediaSurface testnode2("file:///home/bhbn/Videos/fish.mp4"); testnode2.init(); - - ImageSurface testnode3("images/v-mix_256x256.png"); testnode3.init(); testnode3.getShader()->blending = Shader::BLEND_ADD; @@ -375,10 +269,12 @@ int main(int, char**) Group g1; g1.init(); g1.transform_ = glm::translate(glm::identity(), glm::vec3(1.f, 1.f, 0.f)); + g1.transform_ = glm::scale(g1.transform_, glm::vec3(2.f, 2.f, 2.f)); Switch g2; g2.init(); g2.transform_ = glm::translate(glm::identity(), glm::vec3(-1.f, -1.f, 0.f)); + g2.transform_ = glm::rotate(g2.transform_, 0.672f, glm::vec3(0.0f, 0.0f, 1.0f)); // build tree g1.addChild(&testnode3); @@ -394,6 +290,9 @@ int main(int, char**) output = new FrameBuffer(1280, 720); Rendering::manager().PushBackDrawCallback(drawPreview); + // add media player + Rendering::manager().PushBackDrawCallback(drawMediaPlayer); + /// /// Main LOOP /// @@ -402,12 +301,9 @@ int main(int, char**) Rendering::manager().Draw(); } - testmedia.close(); - testmedia2.close(); SessionVisitor savetoxml; scene.accept(savetoxml); - scene.accept(savetoxml); savetoxml.save("/home/bhbn/test.vmx"); UserInterface::manager().Terminate(); diff --git a/snippets.cpp b/snippets.cpp index 00a90dd..ad726b1 100644 --- a/snippets.cpp +++ b/snippets.cpp @@ -1,3 +1,13 @@ + +// old stuff +ImageShader rendering_shader; +MediaPlayer testmedia; +MediaPlayer testmedia2("testmedia2"); +unsigned int vbo, vao, ebo; +float texturear = 1.0; +GLuint textureimagepng = 0; + + GLuint loadPNG(const char *imagepath, float *aspectrato) { int w, h, n, image; @@ -95,4 +105,212 @@ void create_square_glm(unsigned int &vbo, unsigned int &vao, unsigned int &ebo) } +// from https://gstreamer.freedesktop.org/documentation/application-development/advanced/pipeline-manipulation.html?gi-language=c + +void drawMediaBackgound() +{ + if ( !testmedia2.isOpen() ) + return; + + // + // RENDER SOURCE + // + testmedia2.update(); + + // use the shader + rendering_shader.projection = Rendering::manager().Projection(); + rendering_shader.modelview = glm::identity();; + rendering_shader.use(); + // use the media + testmedia2.bind(); + // draw the vertex array + glBindVertexArray(vao); + glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_INT, 0); + glBindVertexArray(0); + glBindTexture(GL_TEXTURE_2D, 0); + + // + // GUI to control SOURCE + // + { + ImGui::Begin("Image properties"); + + // MODEL VIEW + static float translation[] = {0.f, 0.f}; + if (ImGuiToolkit::ButtonIcon(6, 15)) { + translation[0] = 0.f; + translation[1] = 0.f; + } + ImGui::SameLine(0, 10); + ImGui::SliderFloat2("position", translation, -5.0, 5.0); + + static float rotation = 0.f; + if (ImGuiToolkit::ButtonIcon(4, 15)) rotation = 0.f; + ImGui::SameLine(0, 10); + ImGui::SliderFloat("rotation", &rotation, 0, 2 * PI); + + static float scale = 1.f; + if (ImGuiToolkit::ButtonIcon(3, 15)) scale = 1.f; + ImGui::SameLine(0, 10); + ImGui::SliderFloat("scale", &scale, 0.1f, 10.f, "%.3f", 3.f); + + // set modelview +// rendering_shader.setModelview(translation[0], translation[1], rotation, scale, testmedia2.AspectRatio()); + + // color picker + if (ImGuiToolkit::ButtonIcon(16, 8)) rendering_shader.color = glm::vec4(1.f); + ImGui::SameLine(0, 10); + ImGui::ColorEdit3("color", glm::value_ptr(rendering_shader.color) ) ; + // brightness slider + if (ImGuiToolkit::ButtonIcon(4, 1)) rendering_shader.brightness = 0.f; + ImGui::SameLine(0, 10); + ImGui::SliderFloat("brightness", &rendering_shader.brightness, -1.0, 1.0, "%.3f", 2.f); + // contrast slider + if (ImGuiToolkit::ButtonIcon(2, 1)) rendering_shader.contrast = 0.f; + ImGui::SameLine(0, 10); + ImGui::SliderFloat("contrast", &rendering_shader.contrast, -1.0, 1.0, "%.3f", 2.f); + + ImGui::End(); + } + +} + +void drawMediaPlayer() +{ + static GstClockTime begin = GST_CLOCK_TIME_NONE; + static GstClockTime end = GST_CLOCK_TIME_NONE; + + if ( !testmedia.isOpen() ) + return; + + testmedia.update(); + + if ( begin == GST_CLOCK_TIME_NONE) { + + begin = testmedia.duration() / 5; + end = testmedia.duration() / 3; +// if ( testmedia.addPlaySegment(begin, end) ) +// std::cerr << " - first segment " << std::endl; + +// begin *= 2; +// end *= 2; +// if ( testmedia.addPlaySegment(begin, end) ) +// std::cerr << " - second segment " << std::endl; + + } + + ImGui::Begin("Media Player"); + float width = ImGui::GetContentRegionAvail().x; + float spacing = ImGui::GetStyle().ItemInnerSpacing.x; + + ImVec2 imagesize ( width, width / testmedia.aspectRatio()); + ImGui::Image((void*)(intptr_t)testmedia.texture(), imagesize); + + if (ImGui::Button(ICON_FA_FAST_BACKWARD)) + testmedia.rewind(); + ImGui::SameLine(0, spacing); + + // remember playing mode of the GUI + static bool media_playing_mode = testmedia.isPlaying(); + + // display buttons Play/Stop depending on current playing mode + if (media_playing_mode) { + + if (ImGui::Button(ICON_FA_STOP " Stop")) + media_playing_mode = false; + ImGui::SameLine(0, spacing); + + ImGui::PushButtonRepeat(true); + if (ImGui::Button(ICON_FA_FORWARD)) + testmedia.fastForward (); + ImGui::PopButtonRepeat(); + } + else { + + if (ImGui::Button(ICON_FA_PLAY " Play")) + media_playing_mode = true; + ImGui::SameLine(0, spacing); + + ImGui::PushButtonRepeat(true); + if (ImGui::Button(ICON_FA_STEP_FORWARD)) + testmedia.seekNextFrame(); + ImGui::PopButtonRepeat(); + } + + ImGui::SameLine(0, spacing * 2.f); + ImGui::Dummy(ImVec2(width - 700.0, 0)); // right align + + static int current_loop = 1; + static const char* loop_names[3] = { "Stop", "Rewind", "Bounce" }; + const char* current_loop_name = loop_names[current_loop]; + ImGui::SameLine(0, spacing); + if (current_loop == 0) ImGuiToolkit::Icon(0, 15); + else if (current_loop == 1) ImGuiToolkit::Icon(1, 15); + else ImGuiToolkit::Icon(19, 14); + ImGui::SameLine(0, spacing); + ImGui::SetNextItemWidth(90); + if ( ImGui::SliderInt("", ¤t_loop, 0, 2, current_loop_name) ) + testmedia.setLoop( (MediaPlayer::LoopMode) current_loop ); + + float speed = static_cast(testmedia.playSpeed()); + ImGui::SameLine(0, spacing); + ImGui::SetNextItemWidth(270); + // ImGui::SetNextItemWidth(width - 90.0); + if (ImGui::SliderFloat( "Speed", &speed, -10.f, 10.f, "x %.1f", 2.f)) + testmedia.setPlaySpeed( static_cast(speed) ); + ImGui::SameLine(0, spacing); + if (ImGuiToolkit::ButtonIcon(19, 15)) { + speed = 1.f; + testmedia.setPlaySpeed( static_cast(speed) ); + } + + guint64 current_t = testmedia.position(); + guint64 seek_t = current_t; + + bool slider_pressed = ImGuiToolkit::TimelineSlider( "simpletimeline", &seek_t, + testmedia.duration(), testmedia.frameDuration()); + +// std::list > segments = testmedia.getPlaySegments(); +// bool slider_pressed = ImGuiToolkit::TimelineSliderEdit( "timeline", &seek_t, testmedia.Duration(), +// testmedia.FrameDuration(), segments); + +// if (!segments.empty()) { +// // segments have been modified +// g_print("Segments modified \n"); + +// for (std::list< std::pair >::iterator s = segments.begin(); s != segments.end(); s++){ +// MediaSegment newsegment(s->first, s->second); +// testmedia.removeAllPlaySegmentOverlap(newsegment); +// if (!testmedia.addPlaySegment(newsegment)) +// g_print("new Segment could not be added \n"); +// } +// } + + // if the seek target time is different from the current position time + // (i.e. the difference is less than one frame) + if ( ABS_DIFF (current_t, seek_t) > testmedia.frameDuration() ) { + + // request seek (ASYNC) + testmedia.seekTo(seek_t); + } + + // play/stop command should be following the playing mode (buttons) + // AND force to stop when the slider is pressed + bool media_play = media_playing_mode & (!slider_pressed); + + // apply play action to media only if status should change + // NB: The seek command performed an ASYNC state change, but + // gst_element_get_state called in isPlaying() will wait for the state change to complete. + if ( testmedia.isPlaying() != media_play ) { + testmedia.play( media_play ); + } + + // display info + ImGui::Text("%s %d x %d", testmedia.codec().c_str(), testmedia.width(), testmedia.height()); + ImGui::Text("Framerate %.2f / %.2f", testmedia.updateFrameRate() , testmedia.frameRate() ); + + ImGui::End(); +} + +