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/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

View File

@@ -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();

View File

@@ -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)

View File

@@ -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);
}

View File

@@ -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]

View File

@@ -1,6 +1,9 @@
#include <glad/glad.h>
#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;
}

View File

@@ -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;
};

View File

@@ -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

View File

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

View File

@@ -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();

View File

@@ -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);

View File

@@ -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);

View File

@@ -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<ImageShader *>(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<glm::mat4>(), 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;
}
}

View File

@@ -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<View::Mode, Group*> 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_;

View File

@@ -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<float>(Rendering::manager().Width()), static_cast<float>(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<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)
{
currentTextEdit = text;

View File

@@ -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_ */

View File

@@ -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");

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 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

145
main.cpp
View File

@@ -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<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, &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<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();
}
@@ -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

View File

@@ -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

View File

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

View File

@@ -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;