Separate shader for image processing and simple texture display.

ImageShader added a second texture for mask blending. Cleanup of User
Interface windows.
This commit is contained in:
brunoherbelin
2020-04-27 13:44:20 +02:00
parent 1d9e955bfa
commit d248df0567
22 changed files with 303 additions and 210 deletions

View File

@@ -238,7 +238,9 @@ set(VMIX_RSC_FILES
./rsc/fonts/Roboto-Italic.ttf ./rsc/fonts/Roboto-Italic.ttf
./rsc/fonts/fa-regular-400.ttf ./rsc/fonts/fa-regular-400.ttf
./rsc/fonts/fa-solid-900.ttf ./rsc/fonts/fa-solid-900.ttf
./rsc/images/mask_vignette.png
./rsc/images/v-mix_256x256.png ./rsc/images/v-mix_256x256.png
./rsc/images/rgb.png
./rsc/images/busy.png ./rsc/images/busy.png
./rsc/images/icons.dds ./rsc/images/icons.dds
./rsc/images/seed_512.jpg ./rsc/images/seed_512.jpg

View File

@@ -12,19 +12,26 @@ public:
// bind the FrameBuffer as current to draw into // bind the FrameBuffer as current to draw into
void bind(); void bind();
void begin(); // unbind any framebuffer object
void end();
// release any framebuffer object
static void release(); 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 // blit copy to another, returns true on success
bool blit(FrameBuffer *other); 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 width() const { return attrib_.viewport.x; }
inline uint height() const { return attrib_.viewport.y; } inline uint height() const { return attrib_.viewport.y; }
uint texture() const;
float aspectRatio() const; float aspectRatio() const;
// texture index for draw
uint texture() const;
private: private:
void init(); void init();

View File

@@ -133,21 +133,7 @@ void ImGuiVisitor::visit(Shader &n)
void ImGuiVisitor::visit(ImageShader &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) void ImGuiVisitor::visit(ImageProcessingShader &n)

View File

@@ -15,8 +15,8 @@ void ImageProcessingShader::use()
{ {
Shader::use(); Shader::use();
program_->setUniform("iChannelResolution[0]", iChannelResolution[0].x, iChannelResolution[0].y, iChannelResolution[0].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("iChannelResolution[1]", iChannelResolution[1].x, iChannelResolution[1].y, iChannelResolution[1].z);
program_->setUniform("brightness", brightness); program_->setUniform("brightness", brightness);
program_->setUniform("contrast", contrast); program_->setUniform("contrast", contrast);
@@ -41,9 +41,9 @@ void ImageProcessingShader::reset()
{ {
Shader::reset(); Shader::reset();
// no texture resolution yet // // no texture resolution yet
iChannelResolution[0] = glm::vec3(1.f); // iChannelResolution[0] = glm::vec3(1.f);
iChannelResolution[1] = glm::vec3(1.f); // iChannelResolution[1] = glm::vec3(1.f);
// default values for image processing // default values for image processing
brightness = 0.f; brightness = 0.f;
@@ -63,6 +63,6 @@ void ImageProcessingShader::reset()
} }
void ImageProcessingShader::accept(Visitor& v) { void ImageProcessingShader::accept(Visitor& v) {
Shader::accept(v); // Shader::accept(v);
v.visit(*this); v.visit(*this);
} }

View File

@@ -12,12 +12,12 @@ public:
ImageProcessingShader(); ImageProcessingShader();
virtual ~ImageProcessingShader() {} virtual ~ImageProcessingShader() {}
virtual void use(); void use() override;
virtual void reset(); void reset() override;
virtual void accept(Visitor& v); void accept(Visitor& v) override;
// textures resolution // // textures resolution
glm::vec3 iChannelResolution[2]; // glm::vec3 iChannelResolution[2];
// color effects // color effects
float brightness; // [-1 1] float brightness; // [-1 1]

View File

@@ -1,6 +1,9 @@
#include <glad/glad.h>
#include "defines.h" #include "defines.h"
#include "Visitor.h" #include "Visitor.h"
#include "ImageShader.h" #include "ImageShader.h"
#include "Resource.h"
ShadingProgram imageShadingProgram("shaders/image.vs", "shaders/image.fs"); ShadingProgram imageShadingProgram("shaders/image.vs", "shaders/image.fs");
@@ -14,9 +17,12 @@ void ImageShader::use()
{ {
Shader::use(); Shader::use();
program_->setUniform("brightness", brightness);
program_->setUniform("contrast", contrast);
program_->setUniform("stipple", stipple); program_->setUniform("stipple", stipple);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, mask);
glActiveTexture(GL_TEXTURE0);
} }
@@ -24,8 +30,16 @@ void ImageShader::reset()
{ {
Shader::reset(); Shader::reset();
brightness = 0.f; // setup double texturing
contrast = 0.f; program_->use();
program_->setUniform("iChannel0", 0);
program_->setUniform("iChannel1", 1);
program_->enduse();
// default mask (channel1)
mask = Resource::getTextureWhite();
// no stippling
stipple = 0.f; stipple = 0.f;
} }

View File

@@ -10,12 +10,11 @@ public:
ImageShader(); ImageShader();
virtual ~ImageShader() {} virtual ~ImageShader() {}
virtual void use(); void use() override;
virtual void reset(); void reset() override;
virtual void accept(Visitor& v); void accept(Visitor& v) override;
float brightness; uint mask;
float contrast;
float stipple; float stipple;
}; };

View File

@@ -296,14 +296,14 @@ void MediaPlayer::play(bool on)
timecount_.reset(); timecount_.reset();
} }
bool MediaPlayer::isPlaying() const bool MediaPlayer::isPlaying(bool testpipeline) const
{ {
// image cannot play // image cannot play
if (isimage_) if (isimage_)
return false; return false;
// if not ready yet, answer with requested state // if not ready yet, answer with requested state
if ( pipeline_ == nullptr ) if ( !testpipeline || pipeline_ == nullptr )
return desired_state_ == GST_STATE_PLAYING; return desired_state_ == GST_STATE_PLAYING;
// if ready, answer with actual state // if ready, answer with actual state

View File

@@ -123,7 +123,7 @@ public:
/** /**
* Get Pause / Play * Get Pause / Play
* */ * */
bool isPlaying() const; bool isPlaying(bool testpipeline = false) const;
/** /**
* Speed factor for playing * Speed factor for playing
* Can be negative. * Can be negative.

View File

@@ -29,11 +29,11 @@ uint Resource::getTextureBlack()
{ {
static uint tex_index_black = 0; static uint tex_index_black = 0;
// generate texture (once) & clear // generate texture (once)
if (tex_index_black == 0) { if (tex_index_black == 0) {
glGenTextures(1, &tex_index_black); glGenTextures(1, &tex_index_black);
glBindTexture( GL_TEXTURE_2D, 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 // texture with one black pixel
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, clearColor); 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; 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){ const char *Resource::getData(const std::string& path, size_t* out_file_size){
auto fs = cmrc::vmix::get_filesystem(); auto fs = cmrc::vmix::get_filesystem();

View File

@@ -22,9 +22,12 @@ namespace Resource
// Returns the OpenGL generated Texture index // Returns the OpenGL generated Texture index
uint getTextureImage(const std::string& path, float *aspect_ratio = nullptr); 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(); uint getTextureBlack();
// Returns the OpenGL generated Texture index for an empty 1x1 white opaque pixel texture
uint getTextureWhite();
// Generic access to pointer to data // Generic access to pointer to data
const char *getData(const std::string& path, size_t* out_file_size); const char *getData(const std::string& path, size_t* out_file_size);

View File

@@ -159,8 +159,6 @@ void SessionVisitor::visit(ImageShader &n)
xmlCurrent_->SetAttribute("type", "ImageShader"); xmlCurrent_->SetAttribute("type", "ImageShader");
XMLElement *filter = xmlDoc_->NewElement("uniforms"); XMLElement *filter = xmlDoc_->NewElement("uniforms");
filter->SetAttribute("brightness", n.brightness);
filter->SetAttribute("contrast", n.contrast);
filter->SetAttribute("stipple", n.stipple); filter->SetAttribute("stipple", n.stipple);
xmlCurrent_->InsertEndChild(filter); xmlCurrent_->InsertEndChild(filter);

View File

@@ -33,10 +33,13 @@ Source::Source(std::string name) : name_(""), initialized_(false)
Frame *frame = new Frame(Frame::MIXING); Frame *frame = new Frame(Frame::MIXING);
frame->translation_.z = 0.1; frame->translation_.z = 0.1;
groups_[View::MIXING]->addChild(frame); 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 // will be associated to nodes later
mixingshader_ = new ImageShader();
rendershader_ = new ImageProcessingShader(); rendershader_ = new ImageProcessingShader();
renderbuffer_ = nullptr;
rendersurface_ = nullptr;
// add source to the list // add source to the list
sources_.push_front(this); sources_.push_front(this);
@@ -44,8 +47,10 @@ Source::Source(std::string name) : name_(""), initialized_(false)
Source::~Source() Source::~Source()
{ {
// delete shader // delete render objects
delete rendershader_; delete rendershader_;
if (renderbuffer_)
delete renderbuffer_;
// delete groups and their children // delete groups and their children
delete groups_[View::RENDERING]; 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 // - textured with original texture from media player
// - crop & repeat UV can be managed here // - crop & repeat UV can be managed here
// - additional custom shader can be associated // - additional custom shader can be associated
mediasurface_ = new Surface; mediasurface_ = new Surface(rendershader_);
// extra overlay for mixing view // extra overlay for mixing view
mixingoverlay_ = new Frame(Frame::MIXING_OVERLAY); mixingoverlay_ = new Frame(Frame::MIXING_OVERLAY);
@@ -180,18 +185,17 @@ void MediaSource::init()
// create Frame buffer matching size of media player // create Frame buffer matching size of media player
renderbuffer_ = new FrameBuffer(mediaplayer()->width(), mediaplayer()->height()); renderbuffer_ = new FrameBuffer(mediaplayer()->width(), mediaplayer()->height());
// setup shader resolution for texture 0 // // setup shader resolution for texture 0
rendershader_->iChannelResolution[0] = glm::vec3(mediaplayer()->width(), mediaplayer()->height(), 0.f); // rendershader_->iChannelResolution[0] = glm::vec3(mediaplayer()->width(), mediaplayer()->height(), 0.f);
// create the surfaces to draw the frame buffer in the views // create the surfaces to draw the frame buffer in the views
// TODO Provide the source specific effect shader // TODO Provide the source specific effect shader
rendersurface_ = new FrameBufferSurface(renderbuffer_, rendershader_); rendersurface_ = new FrameBufferSurface(renderbuffer_, mixingshader_);
groups_[View::RENDERING]->addChild(rendersurface_); groups_[View::RENDERING]->addChild(rendersurface_);
groups_[View::MIXING]->addChild(rendersurface_); groups_[View::MIXING]->addChild(rendersurface_);
// for mixing view, add another surface to overlay (for stippled view in transparency) // for mixing view, add another surface to overlay (for stippled view in transparency)
Surface *surfacemix = new Surface(); Surface *surfacemix = new FrameBufferSurface(renderbuffer_);
surfacemix->setTextureIndex( mediaplayer_->texture() );
ImageShader *is = static_cast<ImageShader *>(surfacemix->shader()); ImageShader *is = static_cast<ImageShader *>(surfacemix->shader());
if (is) is->stipple = 1.0; if (is) is->stipple = 1.0;
groups_[View::MIXING]->addChild(surfacemix); groups_[View::MIXING]->addChild(surfacemix);
@@ -202,6 +206,8 @@ void MediaSource::init()
(*node)->scale_.x = mediaplayer_->aspectRatio(); (*node)->scale_.x = mediaplayer_->aspectRatio();
} }
// mixingshader_->mask = Resource::getTextureImage("images/mask_vignette.png");
// done init once and for all // done init once and for all
initialized_ = true; initialized_ = true;
} }
@@ -223,15 +229,24 @@ void MediaSource::render(bool current)
mediasurface_->draw(glm::identity<glm::mat4>(), projection); mediasurface_->draw(glm::identity<glm::mat4>(), projection);
renderbuffer_->end(); renderbuffer_->end();
// read position of the mixing node and interpret this as transparency of render output // 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 ); 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 // make Mixing Overlay visible if it is current source
mixingoverlay_->visible_ = current; mixingoverlay_->visible_ = current;
} }
} }
FrameBuffer *MediaSource::frame() const
{
if (initialized_ && renderbuffer_)
{
return renderbuffer_;
}
else {
static FrameBuffer *black = new FrameBuffer(640,480);
return black;
}
}

View File

@@ -7,11 +7,12 @@
#include "View.h" #include "View.h"
class ImageShader;
class ImageProcessingShader; class ImageProcessingShader;
class Surface;
class FrameBuffer; class FrameBuffer;
class MediaPlayer;
class FrameBufferSurface; class FrameBufferSurface;
class MediaPlayer;
class Surface;
class Frame; class Frame;
class Source; class Source;
@@ -34,8 +35,14 @@ public:
// get handle on the node used to manipulate the source in a view // get handle on the node used to manipulate the source in a view
inline Group *group(View::Mode m) const { return groups_.at(m); } inline Group *group(View::Mode m) const { return groups_.at(m); }
// every Source have a shader to control visual effects // every Source has a shader to control image processing effects
inline ImageProcessingShader *shader() const { return rendershader_; } 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 // every Source shall be rendered before draw
virtual void render(bool current) = 0; virtual void render(bool current) = 0;
@@ -60,18 +67,21 @@ protected:
std::map<View::Mode, Group*> groups_; std::map<View::Mode, Group*> groups_;
// render() fills in the renderbuffer at every frame // render() fills in the renderbuffer at every frame
// NB: additional shader (custom) are applied inside render() // NB: rendershader_ is applied at render()
FrameBuffer *renderbuffer_; FrameBuffer *renderbuffer_;
// the rendersurface draws the renderbuffer in the scene // the rendersurface draws the renderbuffer in the scene
// It is associated to the rendershader for mixing effects // It is associated to the rendershader for mixing effects
// (aka visual effect applied in scene, not in render() )
FrameBufferSurface *rendersurface_; FrameBufferSurface *rendersurface_;
// rendershader provides all image processing controls for // rendershader provides image processing controls
// mixing sources in the scene
ImageProcessingShader *rendershader_; ImageProcessingShader *rendershader_;
// mixingshader provides mixing controls
ImageShader *mixingshader_;
Frame *mixingoverlay_;
// static global list of sources // static global list of sources
static SourceList sources_; static SourceList sources_;
}; };
@@ -103,6 +113,8 @@ public:
MediaSource(std::string name, std::string uri); MediaSource(std::string name, std::string uri);
~MediaSource(); ~MediaSource();
FrameBuffer *frame() const;
ImageShader *mixingShader() const;
void render(bool current); void render(bool current);
// Media specific interface // Media specific interface
@@ -113,7 +125,6 @@ protected:
virtual void init(); virtual void init();
Frame *mixingoverlay_;
Surface *mediasurface_; Surface *mediasurface_;
std::string uri_; std::string uri_;
MediaPlayer *mediaplayer_; MediaPlayer *mediaplayer_;

View File

@@ -40,6 +40,8 @@
#include "ImGuiToolkit.h" #include "ImGuiToolkit.h"
#include "GstToolkit.h" #include "GstToolkit.h"
#include "Mixer.h" #include "Mixer.h"
#include "FrameBuffer.h"
#include "MediaPlayer.h"
#include "PickingVisitor.h" #include "PickingVisitor.h"
static std::thread loadThread; static std::thread loadThread;
@@ -75,6 +77,8 @@ UserInterface::UserInterface()
{ {
currentFileDialog = ""; currentFileDialog = "";
currentTextEdit = ""; currentTextEdit = "";
show_preview = true;
show_media_player = false;
} }
bool UserInterface::Init() bool UserInterface::Init()
@@ -265,7 +269,7 @@ void UserInterface::NewFrame()
} }
void UserInterface::Render() void UserInterface::Render()
{ {
ImVec2 geometry(static_cast<float>(Rendering::manager().Width()), static_cast<float>(Rendering::manager().Height())); ImVec2 geometry(static_cast<float>(Rendering::manager().Width()), static_cast<float>(Rendering::manager().Height()));
// file modal dialog // file modal dialog
@@ -283,6 +287,12 @@ void UserInterface::Render()
// warning modal dialog // warning modal dialog
Log::Render(); Log::Render();
// windows
if (show_preview)
RenderPreview();
if (show_media_player)
RenderMediaPlayer();
// Rendering // Rendering
ImGui::Render(); ImGui::Render();
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
@@ -681,7 +691,6 @@ void MainWindow::Render()
ImGui::SetNextWindowPos(ImVec2(40, 40), ImGuiCond_FirstUseEver); ImGui::SetNextWindowPos(ImVec2(40, 40), ImGuiCond_FirstUseEver);
ImGui::SetNextWindowSize(ImVec2(300, 300), ImGuiCond_FirstUseEver); ImGui::SetNextWindowSize(ImVec2(300, 300), ImGuiCond_FirstUseEver);
ImGui::Begin(IMGUI_TITLE_MAINWINDOW, NULL, ImGuiWindowFlags_MenuBar | ImGuiWindowFlags_NoCollapse); ImGui::Begin(IMGUI_TITLE_MAINWINDOW, NULL, ImGuiWindowFlags_MenuBar | ImGuiWindowFlags_NoCollapse);
// Menu Bar // Menu Bar
@@ -703,8 +712,12 @@ void MainWindow::Render()
} }
ImGui::EndMenu(); 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); ImGui::SetNextItemWidth(200);
if ( ImGui::SliderFloat("Scale", &Settings::application.scale, 0.8f, 1.2f, "%.1f")) if ( ImGui::SliderFloat("Scale", &Settings::application.scale, 0.8f, 1.2f, "%.1f"))
ImGui::GetIO().FontGlobalScale = Settings::application.scale; ImGui::GetIO().FontGlobalScale = Settings::application.scale;
@@ -716,7 +729,6 @@ void MainWindow::Render()
} }
if (ImGui::BeginMenu("Tools")) 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_LIST " Logs", "Ctrl+L", &show_logs_window);
ImGui::MenuItem( ICON_FA_TACHOMETER_ALT " Metrics", NULL, &show_overlay_stats); ImGui::MenuItem( ICON_FA_TACHOMETER_ALT " Metrics", NULL, &show_overlay_stats);
if ( ImGui::MenuItem( ICON_FA_CAMERA_RETRO " Screenshot", NULL) ) 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<MediaSource *>(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<int, int> > iconsloop = { {0,15}, {1,15}, {19,14} };
current_loop = (int) mp->loop();
if ( ImGuiToolkit::ButtonIconMultistate(iconsloop, &current_loop) )
mp->setLoop( (MediaPlayer::LoopMode) current_loop );
float speed = static_cast<float>(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<double>(speed) );
ImGui::SameLine(0, spacing);
if (ImGuiToolkit::ButtonIcon(12, 14)) {
speed = 1.f;
mp->setPlaySpeed( static_cast<double>(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) void UserInterface::OpenTextEditor(std::string text)
{ {
currentTextEdit = text; currentTextEdit = text;

View File

@@ -31,8 +31,7 @@ public:
class UserInterface class UserInterface
{ {
// own implementation of ImGui friend class MainWindow;
unsigned int textureicons;
MainWindow mainwindow; MainWindow mainwindow;
std::string currentFileDialog; std::string currentFileDialog;
std::string currentTextEdit; std::string currentTextEdit;
@@ -73,6 +72,12 @@ public:
// //
void OpenTextEditor(std::string text); void OpenTextEditor(std::string text);
protected:
bool show_preview;
void RenderPreview();
bool show_media_player;
void RenderMediaPlayer();
}; };
#endif /* #define __UI_MANAGER_H_ */ #endif /* #define __UI_MANAGER_H_ */

View File

@@ -31,7 +31,7 @@ void View::update(float dt)
MixingView::MixingView() : View() MixingView::MixingView() : View()
{ {
// default settings // 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 // Mixing scene
Mesh *disk = new Mesh("mesh/disk.ply"); Mesh *disk = new Mesh("mesh/disk.ply");

View File

@@ -22,8 +22,9 @@
#define CIRCLE_SQUARE_DIST(x,y) ( (x*x + y*y) / (SCENE_UNIT * SCENE_UNIT * SCENE_UNIT * SCENE_UNIT) ) #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_MAINWINDOW ICON_FA_CIRCLE_NOTCH " v-mix"
#define IMGUI_TITLE_MEDIAPLAYER ICON_FA_FILM " Media Player" #define IMGUI_TITLE_MEDIAPLAYER ICON_FA_FILM " Media Player"
#define IMGUI_TITLE_SHADEREDITOR ICON_FA_CODE " Shader Editor" #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 #define COLOR_BGROUND 0.2, 0.2, 0.2

145
main.cpp
View File

@@ -44,119 +44,18 @@
#define PI 3.14159265358979323846 #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<MediaSource *>(Mixer::manager().currentSource());
if (s) {
mp = s->mediaplayer();
if (mp && mp->isOpen())
show = true;
}
}
ImGui::SetNextWindowPos(ImVec2(200, 200), ImGuiCond_FirstUseEver); ImGui::SetNextWindowPos(ImVec2(200, 200), ImGuiCond_FirstUseEver);
ImGui::SetNextWindowSize(ImVec2(300, 300), ImGuiCond_FirstUseEver); ImGui::SetNextWindowSize(ImVec2(300, 300), ImGuiCond_FirstUseEver);
if ( !ImGui::Begin(IMGUI_TITLE_MEDIAPLAYER, &opened) || !show) if ( !ImGui::Begin("Custom"))
{ {
ImGui::End(); ImGui::End();
return; 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<int, int> > iconsloop = { {0,15}, {1,15}, {19,14} };
current_loop = (int) mp->loop();
if ( ImGuiToolkit::ButtonIconMultistate(iconsloop, &current_loop) )
mp->setLoop( (MediaPlayer::LoopMode) current_loop );
float speed = static_cast<float>(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<double>(speed) );
ImGui::SameLine(0, spacing);
if (ImGuiToolkit::ButtonIcon(12, 14)) {
speed = 1.f;
mp->setPlaySpeed( static_cast<double>(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(); ImGui::End();
} }
@@ -176,31 +75,27 @@ void drawScene()
Source *s = Mixer::manager().currentSource(); Source *s = Mixer::manager().currentSource();
if ( s != nullptr) { 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(); 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**) int main(int, char**)
{ {
@@ -250,11 +145,9 @@ int main(int, char**)
// A.addChild(&P); // A.addChild(&P);
// Mixer::manager().currentView()->scene.root()->addChild(&A); // Mixer::manager().currentView()->scene.root()->addChild(&A);
// preview window // custom test window
Rendering::manager().PushBackDrawCallback(drawPreview); // Rendering::manager().PushBackDrawCallback(drawCustomGui);
// add media player
Rendering::manager().PushBackDrawCallback(drawMediaPlayer);
/// ///
/// Main LOOP /// Main LOOP

View File

@@ -6,22 +6,23 @@ in vec4 vertexColor;
in vec2 vertexUV; in vec2 vertexUV;
uniform sampler2D iChannel0; // input channel (texture id). uniform sampler2D iChannel0; // input channel (texture id).
uniform sampler2D iChannel1; // input mask
uniform vec3 iResolution; // viewport resolution (in pixels) uniform vec3 iResolution; // viewport resolution (in pixels)
uniform vec4 color; uniform vec4 color;
uniform float contrast;
uniform float brightness;
uniform float stipple; uniform float stipple;
void main() void main()
{ {
// color is a mix of texture (manipulated with brightness & contrast), vertex and uniform colors // color is a mix of texture (manipulated with brightness & contrast), vertex and uniform colors
vec4 textureColor = texture(iChannel0, vertexUV); vec4 textureColor = texture(iChannel0, vertexUV);
vec3 RGB = mix(vec3(0.62), textureColor.rgb, contrast + 1.0) + brightness; vec3 RGB = textureColor.rgb * vertexColor.rgb * color.rgb;
RGB *= vertexColor.rgb * color.rgb;
// alpha is a mix of texture alpha, vertex alpha, and uniform alpha affected by stippling // 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; A *= int(gl_FragCoord.x + gl_FragCoord.y) % 2 > (1 - int(stipple)) ? 0.0 : 1.0;
// output RGBA // output RGBA

View File

@@ -19,3 +19,4 @@ void main()
vertexColor = color; vertexColor = color;
vertexUV = texCoord; vertexUV = texCoord;
} }

View File

@@ -31,7 +31,7 @@ uniform vec4 color;
// image processing specific // image processing specific
uniform sampler2D iChannel0; // input channel (texture id). uniform sampler2D iChannel0; // input channel (texture id).
uniform sampler2D iChannel1; 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 vec3 iResolution; // viewport resolution (in pixels)
uniform float contrast; uniform float contrast;
@@ -183,8 +183,7 @@ vec3 convolution(mat3 kernel, vec2 filter_step)
vec3 apply_filter() { vec3 apply_filter() {
vec2 filter_step = vec2( 1.f / iChannelResolution[0].x, 1.f / iChannelResolution[0].y); vec2 filter_step = 1.f / textureSize(iChannel0, 0);
// vec2 filter_step = vec2( 1.f / 1280.0, 1.f / 720.0);
if (filter < 1 || filter > 10) if (filter < 1 || filter > 10)
return texture(iChannel0, vertexUV).rgb; return texture(iChannel0, vertexUV).rgb;