mirror of
https://github.com/brunoherbelin/vimix.git
synced 2025-12-11 10:19:59 +01:00
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:
@@ -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
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -123,7 +123,7 @@ public:
|
||||
/**
|
||||
* Get Pause / Play
|
||||
* */
|
||||
bool isPlaying() const;
|
||||
bool isPlaying(bool testpipeline = false) const;
|
||||
/**
|
||||
* Speed factor for playing
|
||||
* Can be negative.
|
||||
|
||||
20
Resource.cpp
20
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();
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
37
Source.cpp
37
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<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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
29
Source.h
29
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<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_;
|
||||
|
||||
@@ -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, ¤t_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;
|
||||
|
||||
@@ -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_ */
|
||||
|
||||
2
View.cpp
2
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");
|
||||
|
||||
@@ -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
145
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<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, ¤t_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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -19,3 +19,4 @@ void main()
|
||||
vertexColor = color;
|
||||
vertexUV = texCoord;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user