diff --git a/CMakeLists.txt b/CMakeLists.txt index 278f7f4..3add2b9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -238,7 +238,9 @@ set(VMIX_RSC_FILES ./rsc/fonts/Roboto-Italic.ttf ./rsc/fonts/fa-regular-400.ttf ./rsc/fonts/fa-solid-900.ttf + ./rsc/images/mask_vignette.png ./rsc/images/v-mix_256x256.png + ./rsc/images/rgb.png ./rsc/images/busy.png ./rsc/images/icons.dds ./rsc/images/seed_512.jpg diff --git a/FrameBuffer.h b/FrameBuffer.h index 858db32..250fdd0 100644 --- a/FrameBuffer.h +++ b/FrameBuffer.h @@ -12,19 +12,26 @@ public: // bind the FrameBuffer as current to draw into void bind(); - void begin(); - void end(); - - // release any framebuffer object + // unbind any framebuffer object static void release(); + // Bind & push attribs to prepare draw + void begin(); + // pop attrib and unbind to end draw + void end(); // blit copy to another, returns true on success bool blit(FrameBuffer *other); + // clear color + inline void setClearColor(glm::vec3 color) { attrib_.clear_color = color; } + inline glm::vec3 clearColor() const { return attrib_.clear_color; } + + // width & height inline uint width() const { return attrib_.viewport.x; } inline uint height() const { return attrib_.viewport.y; } - uint texture() const; float aspectRatio() const; + // texture index for draw + uint texture() const; private: void init(); diff --git a/ImGuiVisitor.cpp b/ImGuiVisitor.cpp index 4d7ead7..65d4505 100644 --- a/ImGuiVisitor.cpp +++ b/ImGuiVisitor.cpp @@ -133,21 +133,7 @@ void ImGuiVisitor::visit(Shader &n) void ImGuiVisitor::visit(ImageShader &n) { - ImGui::PushID(n.id()); - if (ImGuiToolkit::ButtonIcon(4, 1)) { - n.brightness = 0.f; - n.contrast = 0.f; - } - ImGui::SameLine(0, 10); - ImGui::SetNextItemWidth(RIGHT_ALIGN); - float bc[2] = { n.brightness, n.contrast}; - if ( ImGui::SliderFloat2("B & C", bc, -1.0, 1.0) ) - { - n.brightness = bc[0]; - n.contrast = bc[1]; - } - ImGui::PopID(); } void ImGuiVisitor::visit(ImageProcessingShader &n) diff --git a/ImageProcessingShader.cpp b/ImageProcessingShader.cpp index 0ec345f..c800925 100644 --- a/ImageProcessingShader.cpp +++ b/ImageProcessingShader.cpp @@ -15,8 +15,8 @@ void ImageProcessingShader::use() { Shader::use(); - program_->setUniform("iChannelResolution[0]", iChannelResolution[0].x, iChannelResolution[0].y, iChannelResolution[0].z); - program_->setUniform("iChannelResolution[1]", iChannelResolution[1].x, iChannelResolution[1].y, iChannelResolution[1].z); +// program_->setUniform("iChannelResolution[0]", iChannelResolution[0].x, iChannelResolution[0].y, iChannelResolution[0].z); +// program_->setUniform("iChannelResolution[1]", iChannelResolution[1].x, iChannelResolution[1].y, iChannelResolution[1].z); program_->setUniform("brightness", brightness); program_->setUniform("contrast", contrast); @@ -41,9 +41,9 @@ void ImageProcessingShader::reset() { Shader::reset(); - // no texture resolution yet - iChannelResolution[0] = glm::vec3(1.f); - iChannelResolution[1] = glm::vec3(1.f); +// // no texture resolution yet +// iChannelResolution[0] = glm::vec3(1.f); +// iChannelResolution[1] = glm::vec3(1.f); // default values for image processing brightness = 0.f; @@ -63,6 +63,6 @@ void ImageProcessingShader::reset() } void ImageProcessingShader::accept(Visitor& v) { - Shader::accept(v); +// Shader::accept(v); v.visit(*this); } diff --git a/ImageProcessingShader.h b/ImageProcessingShader.h index 9567338..6fbb316 100644 --- a/ImageProcessingShader.h +++ b/ImageProcessingShader.h @@ -12,12 +12,12 @@ public: ImageProcessingShader(); virtual ~ImageProcessingShader() {} - virtual void use(); - virtual void reset(); - virtual void accept(Visitor& v); + void use() override; + void reset() override; + void accept(Visitor& v) override; - // textures resolution - glm::vec3 iChannelResolution[2]; +// // textures resolution +// glm::vec3 iChannelResolution[2]; // color effects float brightness; // [-1 1] diff --git a/ImageShader.cpp b/ImageShader.cpp index e39e95d..f454ce5 100644 --- a/ImageShader.cpp +++ b/ImageShader.cpp @@ -1,6 +1,9 @@ +#include + #include "defines.h" #include "Visitor.h" #include "ImageShader.h" +#include "Resource.h" ShadingProgram imageShadingProgram("shaders/image.vs", "shaders/image.fs"); @@ -14,9 +17,12 @@ void ImageShader::use() { Shader::use(); - program_->setUniform("brightness", brightness); - program_->setUniform("contrast", contrast); program_->setUniform("stipple", stipple); + + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, mask); + glActiveTexture(GL_TEXTURE0); + } @@ -24,8 +30,16 @@ void ImageShader::reset() { Shader::reset(); - brightness = 0.f; - contrast = 0.f; + // setup double texturing + program_->use(); + program_->setUniform("iChannel0", 0); + program_->setUniform("iChannel1", 1); + program_->enduse(); + + // default mask (channel1) + mask = Resource::getTextureWhite(); + + // no stippling stipple = 0.f; } diff --git a/ImageShader.h b/ImageShader.h index b445304..a9df308 100644 --- a/ImageShader.h +++ b/ImageShader.h @@ -10,12 +10,11 @@ public: ImageShader(); virtual ~ImageShader() {} - virtual void use(); - virtual void reset(); - virtual void accept(Visitor& v); + void use() override; + void reset() override; + void accept(Visitor& v) override; - float brightness; - float contrast; + uint mask; float stipple; }; diff --git a/MediaPlayer.cpp b/MediaPlayer.cpp index 52b256e..89a3ea2 100644 --- a/MediaPlayer.cpp +++ b/MediaPlayer.cpp @@ -296,14 +296,14 @@ void MediaPlayer::play(bool on) timecount_.reset(); } -bool MediaPlayer::isPlaying() const +bool MediaPlayer::isPlaying(bool testpipeline) const { // image cannot play if (isimage_) return false; // if not ready yet, answer with requested state - if ( pipeline_ == nullptr ) + if ( !testpipeline || pipeline_ == nullptr ) return desired_state_ == GST_STATE_PLAYING; // if ready, answer with actual state diff --git a/MediaPlayer.h b/MediaPlayer.h index 5e17087..141e3be 100644 --- a/MediaPlayer.h +++ b/MediaPlayer.h @@ -123,7 +123,7 @@ public: /** * Get Pause / Play * */ - bool isPlaying() const; + bool isPlaying(bool testpipeline = false) const; /** * Speed factor for playing * Can be negative. diff --git a/Resource.cpp b/Resource.cpp index 2842c6f..c63a1fc 100644 --- a/Resource.cpp +++ b/Resource.cpp @@ -29,11 +29,11 @@ uint Resource::getTextureBlack() { static uint tex_index_black = 0; - // generate texture (once) & clear + // generate texture (once) if (tex_index_black == 0) { glGenTextures(1, &tex_index_black); glBindTexture( GL_TEXTURE_2D, tex_index_black); - unsigned char clearColor[4] = {0}; + unsigned char clearColor[4] = {0, 0, 0, 0}; // texture with one black pixel glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, clearColor); } @@ -41,6 +41,22 @@ uint Resource::getTextureBlack() return tex_index_black; } +uint Resource::getTextureWhite() +{ + static uint tex_index_white = 0; + + // generate texture (once) + if (tex_index_white == 0) { + glGenTextures(1, &tex_index_white); + glBindTexture( GL_TEXTURE_2D, tex_index_white); + unsigned char clearColor[4] = {255, 255, 255, 255}; + // texture with one black pixel + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, clearColor); + } + + return tex_index_white; +} + const char *Resource::getData(const std::string& path, size_t* out_file_size){ auto fs = cmrc::vmix::get_filesystem(); diff --git a/Resource.h b/Resource.h index 5c8b17c..9a6929d 100644 --- a/Resource.h +++ b/Resource.h @@ -22,9 +22,12 @@ namespace Resource // Returns the OpenGL generated Texture index uint getTextureImage(const std::string& path, float *aspect_ratio = nullptr); - // Returns the OpenGL generated Texture index for an empty 1x1 black pixel texture + // Returns the OpenGL generated Texture index for an empty 1x1 black transparent pixel texture uint getTextureBlack(); + // Returns the OpenGL generated Texture index for an empty 1x1 white opaque pixel texture + uint getTextureWhite(); + // Generic access to pointer to data const char *getData(const std::string& path, size_t* out_file_size); diff --git a/SessionVisitor.cpp b/SessionVisitor.cpp index a957c0e..bf6aca7 100644 --- a/SessionVisitor.cpp +++ b/SessionVisitor.cpp @@ -159,8 +159,6 @@ void SessionVisitor::visit(ImageShader &n) xmlCurrent_->SetAttribute("type", "ImageShader"); XMLElement *filter = xmlDoc_->NewElement("uniforms"); - filter->SetAttribute("brightness", n.brightness); - filter->SetAttribute("contrast", n.contrast); filter->SetAttribute("stipple", n.stipple); xmlCurrent_->InsertEndChild(filter); diff --git a/Source.cpp b/Source.cpp index ef47ae9..d5426e6 100644 --- a/Source.cpp +++ b/Source.cpp @@ -33,10 +33,13 @@ Source::Source(std::string name) : name_(""), initialized_(false) Frame *frame = new Frame(Frame::MIXING); frame->translation_.z = 0.1; groups_[View::MIXING]->addChild(frame); - groups_[View::MIXING]->scale_ = glm::vec3(0.2f, 0.2f, 1.f); + groups_[View::MIXING]->scale_ = glm::vec3(0.15f, 0.15f, 1.f); // will be associated to nodes later + mixingshader_ = new ImageShader(); rendershader_ = new ImageProcessingShader(); + renderbuffer_ = nullptr; + rendersurface_ = nullptr; // add source to the list sources_.push_front(this); @@ -44,8 +47,10 @@ Source::Source(std::string name) : name_(""), initialized_(false) Source::~Source() { - // delete shader + // delete render objects delete rendershader_; + if (renderbuffer_) + delete renderbuffer_; // delete groups and their children delete groups_[View::RENDERING]; @@ -137,7 +142,7 @@ MediaSource::MediaSource(std::string name, std::string uri) : Source(name), uri_ // - textured with original texture from media player // - crop & repeat UV can be managed here // - additional custom shader can be associated - mediasurface_ = new Surface; + mediasurface_ = new Surface(rendershader_); // extra overlay for mixing view mixingoverlay_ = new Frame(Frame::MIXING_OVERLAY); @@ -180,18 +185,17 @@ void MediaSource::init() // create Frame buffer matching size of media player renderbuffer_ = new FrameBuffer(mediaplayer()->width(), mediaplayer()->height()); - // setup shader resolution for texture 0 - rendershader_->iChannelResolution[0] = glm::vec3(mediaplayer()->width(), mediaplayer()->height(), 0.f); +// // setup shader resolution for texture 0 +// rendershader_->iChannelResolution[0] = glm::vec3(mediaplayer()->width(), mediaplayer()->height(), 0.f); // create the surfaces to draw the frame buffer in the views // TODO Provide the source specific effect shader - rendersurface_ = new FrameBufferSurface(renderbuffer_, rendershader_); + rendersurface_ = new FrameBufferSurface(renderbuffer_, mixingshader_); groups_[View::RENDERING]->addChild(rendersurface_); groups_[View::MIXING]->addChild(rendersurface_); // for mixing view, add another surface to overlay (for stippled view in transparency) - Surface *surfacemix = new Surface(); - surfacemix->setTextureIndex( mediaplayer_->texture() ); + Surface *surfacemix = new FrameBufferSurface(renderbuffer_); ImageShader *is = static_cast(surfacemix->shader()); if (is) is->stipple = 1.0; groups_[View::MIXING]->addChild(surfacemix); @@ -202,6 +206,8 @@ void MediaSource::init() (*node)->scale_.x = mediaplayer_->aspectRatio(); } +// mixingshader_->mask = Resource::getTextureImage("images/mask_vignette.png"); + // done init once and for all initialized_ = true; } @@ -223,15 +229,24 @@ void MediaSource::render(bool current) mediasurface_->draw(glm::identity(), projection); renderbuffer_->end(); - // read position of the mixing node and interpret this as transparency of render output float alpha = 1.0 - CLAMP( SQUARE( glm::length(groups_[View::MIXING]->translation_) ), 0.f, 1.f ); - rendershader_->color.a = alpha; - + mixingshader_->color.a = alpha; // make Mixing Overlay visible if it is current source mixingoverlay_->visible_ = current; } } +FrameBuffer *MediaSource::frame() const +{ + if (initialized_ && renderbuffer_) + { + return renderbuffer_; + } + else { + static FrameBuffer *black = new FrameBuffer(640,480); + return black; + } +} diff --git a/Source.h b/Source.h index ce8c460..e3e541c 100644 --- a/Source.h +++ b/Source.h @@ -7,11 +7,12 @@ #include "View.h" +class ImageShader; class ImageProcessingShader; -class Surface; class FrameBuffer; -class MediaPlayer; class FrameBufferSurface; +class MediaPlayer; +class Surface; class Frame; class Source; @@ -34,8 +35,14 @@ public: // get handle on the node used to manipulate the source in a view inline Group *group(View::Mode m) const { return groups_.at(m); } - // every Source have a shader to control visual effects - inline ImageProcessingShader *shader() const { return rendershader_; } + // every Source has a shader to control image processing effects + inline ImageProcessingShader *processingShader() const { return rendershader_; } + + // every Source has a shader to control mixing effects + inline ImageShader *mixingShader() const { return mixingshader_; } + + // every Source shall have a frame buffer + virtual FrameBuffer *frame() const = 0; // every Source shall be rendered before draw virtual void render(bool current) = 0; @@ -60,18 +67,21 @@ protected: std::map groups_; // render() fills in the renderbuffer at every frame - // NB: additional shader (custom) are applied inside render() + // NB: rendershader_ is applied at render() FrameBuffer *renderbuffer_; // the rendersurface draws the renderbuffer in the scene // It is associated to the rendershader for mixing effects - // (aka visual effect applied in scene, not in render() ) FrameBufferSurface *rendersurface_; - // rendershader provides all image processing controls for - // mixing sources in the scene + // rendershader provides image processing controls ImageProcessingShader *rendershader_; + // mixingshader provides mixing controls + ImageShader *mixingshader_; + + Frame *mixingoverlay_; + // static global list of sources static SourceList sources_; }; @@ -103,6 +113,8 @@ public: MediaSource(std::string name, std::string uri); ~MediaSource(); + FrameBuffer *frame() const; + ImageShader *mixingShader() const; void render(bool current); // Media specific interface @@ -113,7 +125,6 @@ protected: virtual void init(); - Frame *mixingoverlay_; Surface *mediasurface_; std::string uri_; MediaPlayer *mediaplayer_; diff --git a/UserInterfaceManager.cpp b/UserInterfaceManager.cpp index bf9d1be..b32a1dc 100644 --- a/UserInterfaceManager.cpp +++ b/UserInterfaceManager.cpp @@ -40,6 +40,8 @@ #include "ImGuiToolkit.h" #include "GstToolkit.h" #include "Mixer.h" +#include "FrameBuffer.h" +#include "MediaPlayer.h" #include "PickingVisitor.h" static std::thread loadThread; @@ -75,6 +77,8 @@ UserInterface::UserInterface() { currentFileDialog = ""; currentTextEdit = ""; + show_preview = true; + show_media_player = false; } bool UserInterface::Init() @@ -265,7 +269,7 @@ void UserInterface::NewFrame() } void UserInterface::Render() -{ +{ ImVec2 geometry(static_cast(Rendering::manager().Width()), static_cast(Rendering::manager().Height())); // file modal dialog @@ -283,6 +287,12 @@ void UserInterface::Render() // warning modal dialog Log::Render(); + // windows + if (show_preview) + RenderPreview(); + if (show_media_player) + RenderMediaPlayer(); + // Rendering ImGui::Render(); ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); @@ -681,7 +691,6 @@ void MainWindow::Render() ImGui::SetNextWindowPos(ImVec2(40, 40), ImGuiCond_FirstUseEver); ImGui::SetNextWindowSize(ImVec2(300, 300), ImGuiCond_FirstUseEver); - ImGui::Begin(IMGUI_TITLE_MAINWINDOW, NULL, ImGuiWindowFlags_MenuBar | ImGuiWindowFlags_NoCollapse); // Menu Bar @@ -703,8 +712,12 @@ void MainWindow::Render() } ImGui::EndMenu(); } - if (ImGui::BeginMenu("Appearance")) + if (ImGui::BeginMenu("Windows")) { + ImGui::MenuItem( IMGUI_TITLE_PREVIEW, NULL, &UserInterface::manager().show_preview); + ImGui::MenuItem( IMGUI_TITLE_MEDIAPLAYER, NULL, &UserInterface::manager().show_media_player); + ImGui::MenuItem( IMGUI_TITLE_SHADEREDITOR, NULL, &show_editor_window); + ImGui::MenuItem("Appearance", NULL, false, false); ImGui::SetNextItemWidth(200); if ( ImGui::SliderFloat("Scale", &Settings::application.scale, 0.8f, 1.2f, "%.1f")) ImGui::GetIO().FontGlobalScale = Settings::application.scale; @@ -716,7 +729,6 @@ void MainWindow::Render() } if (ImGui::BeginMenu("Tools")) { - ImGui::MenuItem( ICON_FA_CODE " Shader Editor", NULL, &show_editor_window); ImGui::MenuItem( ICON_FA_LIST " Logs", "Ctrl+L", &show_logs_window); ImGui::MenuItem( ICON_FA_TACHOMETER_ALT " Metrics", NULL, &show_overlay_stats); if ( ImGui::MenuItem( ICON_FA_CAMERA_RETRO " Screenshot", NULL) ) @@ -811,6 +823,136 @@ void MainWindow::Render() } } +void UserInterface::RenderPreview() +{ + FrameBuffer *output = Mixer::manager().frame(); + if (output) + { + ImGui::SetNextWindowPos(ImVec2(100, 300), ImGuiCond_FirstUseEver); + ImGui::SetNextWindowSize(ImVec2(640, 480), ImGuiCond_FirstUseEver); + ImGui::Begin(ICON_FA_LAPTOP " Preview", &show_preview, ImGuiWindowFlags_NoScrollbar); + float width = ImGui::GetContentRegionAvail().x; + + ImVec2 imagesize ( width, width / output->aspectRatio()); + ImGui::Image((void*)(intptr_t)output->texture(), imagesize, ImVec2(0.f, 0.f), ImVec2(1.f, -1.f)); + + ImGui::End(); + } +} + +void UserInterface::RenderMediaPlayer() +{ + bool show = false; + MediaPlayer *mp = nullptr; + MediaSource *s = nullptr; + if ( Mixer::manager().currentSource()) { + s = static_cast(Mixer::manager().currentSource()); + if (s) { + mp = s->mediaplayer(); + if (mp && mp->isOpen()) + show = true; + } + } + + ImGui::SetNextWindowPos(ImVec2(200, 200), ImGuiCond_FirstUseEver); + ImGui::SetNextWindowSize(ImVec2(300, 300), ImGuiCond_FirstUseEver); + + if ( !ImGui::Begin(IMGUI_TITLE_MEDIAPLAYER, &show_media_player, ImGuiWindowFlags_NoScrollbar) || !show) + { + ImGui::End(); + return; + } + + float width = ImGui::GetContentRegionAvail().x; + float spacing = ImGui::GetStyle().ItemInnerSpacing.x; + + ImVec2 imagesize ( width, width / mp->aspectRatio()); + ImGui::Image((void*)(uintptr_t)mp->texture(), imagesize); + if (ImGui::IsItemHovered()) { + ImGui::SameLine(-1); + ImGui::Text(" %s %d x %d\n Framerate %.2f / %.2f", mp->codec().c_str(), mp->width(), mp->height(), mp->updateFrameRate() , mp->frameRate() ); + } + + if (ImGui::Button(ICON_FA_FAST_BACKWARD)) + mp->rewind(); + ImGui::SameLine(0, spacing); + + // remember playing mode of the GUI + bool media_playing_mode = mp->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)) + mp->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)) + mp->seekNextFrame(); + ImGui::PopButtonRepeat(); + } + + ImGui::SameLine(0, spacing * 4.f); + + static int current_loop = 0; + static std::vector< std::pair > iconsloop = { {0,15}, {1,15}, {19,14} }; + current_loop = (int) mp->loop(); + if ( ImGuiToolkit::ButtonIconMultistate(iconsloop, ¤t_loop) ) + mp->setLoop( (MediaPlayer::LoopMode) current_loop ); + + float speed = static_cast(mp->playSpeed()); + ImGui::SameLine(0, spacing); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x - 40.0); + // ImGui::SetNextItemWidth(width - 90.0); + if (ImGui::DragFloat( "##Speed", &speed, 0.01f, -10.f, 10.f, "Speed x %.1f", 2.f)) + mp->setPlaySpeed( static_cast(speed) ); + ImGui::SameLine(0, spacing); + if (ImGuiToolkit::ButtonIcon(12, 14)) { + speed = 1.f; + mp->setPlaySpeed( static_cast(speed) ); + mp->setLoop( MediaPlayer::LOOP_REWIND ); + } + + guint64 current_t = mp->position(); + guint64 seek_t = current_t; + + bool slider_pressed = ImGuiToolkit::TimelineSlider( "simpletimeline", &seek_t, + 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) > mp->frameDuration() ) { + + // request seek (ASYNC) + mp->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 ( mp->isPlaying(true) != media_play ) { + mp->play( media_play ); + } + + ImGui::End(); +} + void UserInterface::OpenTextEditor(std::string text) { currentTextEdit = text; diff --git a/UserInterfaceManager.h b/UserInterfaceManager.h index 481ab0b..4f2bfb5 100644 --- a/UserInterfaceManager.h +++ b/UserInterfaceManager.h @@ -31,8 +31,7 @@ public: class UserInterface { - // own implementation of ImGui - unsigned int textureicons; + friend class MainWindow; MainWindow mainwindow; std::string currentFileDialog; std::string currentTextEdit; @@ -73,6 +72,12 @@ public: // void OpenTextEditor(std::string text); +protected: + bool show_preview; + void RenderPreview(); + bool show_media_player; + void RenderMediaPlayer(); + }; #endif /* #define __UI_MANAGER_H_ */ diff --git a/View.cpp b/View.cpp index cc7e766..18ec17e 100644 --- a/View.cpp +++ b/View.cpp @@ -31,7 +31,7 @@ void View::update(float dt) MixingView::MixingView() : View() { // default settings - scene.root()->scale_ = glm::vec3(1.4, 1.4, 1.0); + scene.root()->scale_ = glm::vec3(1.6, 1.6, 1.0); // Mixing scene Mesh *disk = new Mesh("mesh/disk.ply"); diff --git a/defines.h b/defines.h index 8ed99c1..2023ada 100644 --- a/defines.h +++ b/defines.h @@ -22,8 +22,9 @@ #define CIRCLE_SQUARE_DIST(x,y) ( (x*x + y*y) / (SCENE_UNIT * SCENE_UNIT * SCENE_UNIT * SCENE_UNIT) ) #define IMGUI_TITLE_MAINWINDOW ICON_FA_CIRCLE_NOTCH " v-mix" -#define IMGUI_TITLE_MEDIAPLAYER ICON_FA_FILM " Media Player" -#define IMGUI_TITLE_SHADEREDITOR ICON_FA_CODE " Shader Editor" +#define IMGUI_TITLE_MEDIAPLAYER ICON_FA_FILM " Media Player" +#define IMGUI_TITLE_SHADEREDITOR ICON_FA_CODE " Shader Editor" +#define IMGUI_TITLE_PREVIEW ICON_FA_LAPTOP " Preview" #define COLOR_BGROUND 0.2, 0.2, 0.2 diff --git a/main.cpp b/main.cpp index f741f35..9ced7d3 100644 --- a/main.cpp +++ b/main.cpp @@ -44,119 +44,18 @@ #define PI 3.14159265358979323846 -void drawMediaPlayer() +void drawCustomGui() { - static bool opened = true; - static GstClockTime begin = GST_CLOCK_TIME_NONE; - static GstClockTime end = GST_CLOCK_TIME_NONE; - - bool show = false; - MediaPlayer *mp = nullptr; - if ( Mixer::manager().currentSource()) { - MediaSource *s = static_cast(Mixer::manager().currentSource()); - if (s) { - mp = s->mediaplayer(); - if (mp && mp->isOpen()) - show = true; - } - } ImGui::SetNextWindowPos(ImVec2(200, 200), ImGuiCond_FirstUseEver); ImGui::SetNextWindowSize(ImVec2(300, 300), ImGuiCond_FirstUseEver); - if ( !ImGui::Begin(IMGUI_TITLE_MEDIAPLAYER, &opened) || !show) + if ( !ImGui::Begin("Custom")) { ImGui::End(); return; } - float width = ImGui::GetContentRegionAvail().x; - float spacing = ImGui::GetStyle().ItemInnerSpacing.x; - - ImVec2 imagesize ( width, width / mp->aspectRatio()); - ImGui::Image((void*)(intptr_t)mp->texture(), imagesize); - - if (ImGui::Button(ICON_FA_FAST_BACKWARD)) - mp->rewind(); - ImGui::SameLine(0, spacing); - - // remember playing mode of the GUI - bool media_playing_mode = mp->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)) - mp->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)) - mp->seekNextFrame(); - ImGui::PopButtonRepeat(); - } - - ImGui::SameLine(0, spacing * 4.f); -// ImGui::Dummy(ImVec2(width - 700.0, 0)); // right align - - static int current_loop = 0; - static std::vector< std::pair > iconsloop = { {0,15}, {1,15}, {19,14} }; - current_loop = (int) mp->loop(); - if ( ImGuiToolkit::ButtonIconMultistate(iconsloop, ¤t_loop) ) - mp->setLoop( (MediaPlayer::LoopMode) current_loop ); - - float speed = static_cast(mp->playSpeed()); - ImGui::SameLine(0, spacing); - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x - 40.0); - // ImGui::SetNextItemWidth(width - 90.0); - if (ImGui::DragFloat( "##Speed", &speed, 0.01f, -10.f, 10.f, "Speed x %.1f", 2.f)) - mp->setPlaySpeed( static_cast(speed) ); - ImGui::SameLine(0, spacing); - if (ImGuiToolkit::ButtonIcon(12, 14)) { - speed = 1.f; - mp->setPlaySpeed( static_cast(speed) ); - mp->setLoop( MediaPlayer::LOOP_REWIND ); - } - - guint64 current_t = mp->position(); - guint64 seek_t = current_t; - - bool slider_pressed = ImGuiToolkit::TimelineSlider( "simpletimeline", &seek_t, - 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) > mp->frameDuration() ) { - - // request seek (ASYNC) - mp->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 ( mp->isPlaying() != media_play ) { - mp->play( media_play ); - } - - // display info -// 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(); } @@ -176,31 +75,27 @@ void drawScene() Source *s = Mixer::manager().currentSource(); if ( s != nullptr) { - s->shader()->accept(v); + + static char buf5[128]; + sprintf ( buf5, "%s", s->name().c_str() ); + ImGui::SetNextItemWidth(-100); + if (ImGui::InputText("Name", buf5, 64, ImGuiInputTextFlags_CharsNoBlank)){ + s->rename(buf5); + } + + s->mixingShader()->accept(v); + + float width = ImGui::GetContentRegionAvail().x - 100; + ImVec2 imagesize ( width, width / s->frame()->aspectRatio()); + ImGui::Image((void*)(uintptr_t) s->frame()->texture(), imagesize); + + s->processingShader()->accept(v); } ImGui::End(); } -void drawPreview() -{ - FrameBuffer *output = Mixer::manager().frame(); - if (output) - { - 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()); - ImGui::Image((void*)(intptr_t)output->texture(), imagesize, ImVec2(0.f, 0.f), ImVec2(1.f, -1.f)); - - ImGui::End(); - } - -} - int main(int, char**) { @@ -250,11 +145,9 @@ int main(int, char**) // A.addChild(&P); // Mixer::manager().currentView()->scene.root()->addChild(&A); - // preview window - Rendering::manager().PushBackDrawCallback(drawPreview); + // custom test window +// Rendering::manager().PushBackDrawCallback(drawCustomGui); - // add media player - Rendering::manager().PushBackDrawCallback(drawMediaPlayer); /// /// Main LOOP diff --git a/rsc/shaders/image.fs b/rsc/shaders/image.fs index 6426dd3..947ac15 100644 --- a/rsc/shaders/image.fs +++ b/rsc/shaders/image.fs @@ -6,22 +6,23 @@ in vec4 vertexColor; in vec2 vertexUV; uniform sampler2D iChannel0; // input channel (texture id). +uniform sampler2D iChannel1; // input mask uniform vec3 iResolution; // viewport resolution (in pixels) uniform vec4 color; -uniform float contrast; -uniform float brightness; uniform float stipple; void main() { // color is a mix of texture (manipulated with brightness & contrast), vertex and uniform colors vec4 textureColor = texture(iChannel0, vertexUV); - vec3 RGB = mix(vec3(0.62), textureColor.rgb, contrast + 1.0) + brightness; - RGB *= vertexColor.rgb * color.rgb; + vec3 RGB = textureColor.rgb * vertexColor.rgb * color.rgb; // alpha is a mix of texture alpha, vertex alpha, and uniform alpha affected by stippling - float A = textureColor.a * vertexColor.a * color.a; + vec4 maskColor = texture(iChannel1, vertexUV); + float maskIntensity = (maskColor.r + maskColor.g + maskColor.b) / 3.0; + + float A = textureColor.a * vertexColor.a * color.a * maskIntensity; A *= int(gl_FragCoord.x + gl_FragCoord.y) % 2 > (1 - int(stipple)) ? 0.0 : 1.0; // output RGBA diff --git a/rsc/shaders/image.vs b/rsc/shaders/image.vs index 38edf2e..0adcc07 100644 --- a/rsc/shaders/image.vs +++ b/rsc/shaders/image.vs @@ -19,3 +19,4 @@ void main() vertexColor = color; vertexUV = texCoord; } + diff --git a/rsc/shaders/imageprocessing.fs b/rsc/shaders/imageprocessing.fs index 0541d49..a80b549 100644 --- a/rsc/shaders/imageprocessing.fs +++ b/rsc/shaders/imageprocessing.fs @@ -31,7 +31,7 @@ uniform vec4 color; // image processing specific uniform sampler2D iChannel0; // input channel (texture id). uniform sampler2D iChannel1; -uniform vec3 iChannelResolution[2]; // input channel resolution (in pixels) +//uniform vec3 iChannelResolution[2]; // input channel resolution (in pixels) uniform vec3 iResolution; // viewport resolution (in pixels) uniform float contrast; @@ -183,8 +183,7 @@ vec3 convolution(mat3 kernel, vec2 filter_step) vec3 apply_filter() { - vec2 filter_step = vec2( 1.f / iChannelResolution[0].x, 1.f / iChannelResolution[0].y); -// vec2 filter_step = vec2( 1.f / 1280.0, 1.f / 720.0); + vec2 filter_step = 1.f / textureSize(iChannel0, 0); if (filter < 1 || filter > 10) return texture(iChannel0, vertexUV).rgb;