BugFix Important fix of Bundle Session source

premultiply alpha should NOT be applied to render session in framebuffer with alpha on surface : added a uniform to image shader to allow this. Fixed other problems related to creation and expand of bundle sources. Added a button to bundle a single source.
This commit is contained in:
Bruno Herbelin
2025-01-01 23:55:39 +01:00
parent a36a7fe4b2
commit 40d3f83719
8 changed files with 67 additions and 21 deletions
+2 -1
View File
@@ -14,6 +14,7 @@ uniform vec4 color;
uniform sampler2D iChannel0; // input channel (texture id).
uniform sampler2D iChannel1; // input mask
uniform float stipple;
uniform float premultiply;
void main()
{
@@ -33,5 +34,5 @@ void main()
A = clamp(A, 0.0, 1.0);
// output RGB with Alpha pre-multiplied
FragColor = vec4(RGB * A, A);
FragColor = vec4(RGB * mix(1.0 / max(A, 0.001), A, premultiply), A);
}
+2 -1
View File
@@ -43,7 +43,7 @@ const char* MaskShader::mask_icons[4] = { ICON_FA_WINDOW_CLOSE, ICON_FA_EDIT, I
const char* MaskShader::mask_names[4] = { "Mask None", "Mask Paint", "Mask Shape", "Mask Source" };
const char* MaskShader::mask_shapes[5] = { "Ellipse", "Oblong", "Rectangle", "Horizontal", "Vertical" };
ImageShader::ImageShader(): Shader(), secondary_texture(0), stipple(0.f)
ImageShader::ImageShader(): Shader(), secondary_texture(0), stipple(0.f), premultiply(1.f)
{
// static program shader
program_ = &imageShadingProgram;
@@ -57,6 +57,7 @@ void ImageShader::use()
// set stippling
program_->setUniform("stipple", stipple);
program_->setUniform("premultiply", premultiply);
program_->setUniform("iNodes", iNodes);
// default mask
+1
View File
@@ -20,6 +20,7 @@ public:
// uniforms
float stipple;
float premultiply;
glm::mat4 iNodes;
};
+29 -8
View File
@@ -771,8 +771,27 @@ void Mixer::groupSelection()
if (selection().empty())
return;
// work on non-empty selection of sources
auto _selection = selection().getCopy();
// group the current selection
group(selection().getCopy());
}
void Mixer::groupCurrent()
{
if ( current_source_ != session_->end() ) {
SourceList L;
L.emplace_front( *current_source_ );
// group the current selection
group( L );
}
}
void Mixer::group(SourceList sourcelist)
{
// work on non-empty list of sources
if (sourcelist.empty())
return;
// create session group where to transfer sources into
SessionGroupSource *sessiongroup = new SessionGroupSource;
@@ -781,25 +800,25 @@ void Mixer::groupSelection()
// prepare for new session group name
std::string name;
// prepare for depth to place the group source
float d = _selection.front()->depth();
float d = sourcelist.front()->depth();
// remember groups before emptying the session
std::list<SourceList> allgroups = session_->getMixingGroups();
std::list<SourceList> selectgroups;
for (auto git = allgroups.begin(); git != allgroups.end(); ++git){
selectgroups.push_back( intersect( *git, _selection));
selectgroups.push_back( intersect( *git, sourcelist));
}
// browse the selection
for (auto sit = _selection.begin(); sit != _selection.end(); ++sit) {
// browse the list
for (auto sit = sourcelist.begin(); sit != sourcelist.end(); ++sit) {
// import source into group
if ( sessiongroup->import(*sit) ) {
// find lower depth in _selection
// find lower depth in list
d = MIN( (*sit)->depth(), d);
// generate name from intials of all sources
name += (*sit)->initials();
// detach & remove element from selection()
// detach & remove element from list
detachSource (*sit);
// remove source from session
session_->removeSource(*sit);
@@ -813,6 +832,7 @@ void Mixer::groupSelection()
// set depth at given location
sessiongroup->group(View::LAYER)->translation_.z = d;
sessiongroup->group(View::RENDERING)->translation_.z = d;
// set alpha to full opacity
sessiongroup->group(View::MIXING)->translation_.x = 0.f;
@@ -1498,6 +1518,7 @@ void Mixer::merge(SessionSource *source)
// avoid display issues
current_view_->update(0.f);
unsetCurrentSource();
// new state in history manager
Action::manager().store(info.str());
+4 -2
View File
@@ -69,8 +69,9 @@ public:
int numSource () const;
// operations on selection
void deleteSelection ();
void groupSelection ();
void deleteSelection ();
void groupSelection ();
void groupCurrent ();
void groupAll (bool only_active = false);
void ungroupAll ();
void groupSession ();
@@ -148,6 +149,7 @@ protected:
void attachSource (Source *s);
void detachSource (Source *s);
bool attached (Source *s) const;
void group (SourceList sources);
void setCurrentSource(SourceList::iterator it);
SourceList::iterator current_source_;
+5
View File
@@ -447,6 +447,11 @@ void SessionGroupSource::init()
// get the texture index from framebuffer of session, apply it to the surface
texturesurface_->setTextureIndex( session_->frame()->texture() );
// special case for session group using FrameBuffer_alpha
// shader should not pre-multiply alpha
ImageShader *ish = static_cast<ImageShader *>(texturesurface_->shader());
ish->premultiply = 0.f;
// create Frame buffer matching size of session
FrameBuffer *renderbuffer = new FrameBuffer( session_->frame()->resolution(), FrameBuffer::FrameBuffer_alpha );
+2 -1
View File
@@ -930,6 +930,7 @@ void Source::update(float dt)
static glm::mat4 UVtoScene = GlmToolkit::transform(glm::vec3(1.f, -1.f, 0.f),
glm::vec3(0.f, 0.f, 0.f),
glm::vec3(-2.f, 2.f, 1.f));
static glm::mat4 ScenetoUV = glm::inverse(UVtoScene);
// Aspect Ratio correction transform : coordinates of Appearance Frame are scaled by render buffer width
glm::mat4 Ar = glm::scale(glm::identity<glm::mat4>(), glm::vec3(renderbuffer_->aspectRatio(), 1.f, 1.f) );
// Translation : same as Appearance Frame (modified by Ar)
@@ -948,7 +949,7 @@ void Source::update(float dt)
// 5. Revert aspect ration correction
// 6. Apply the Scaling (independent of aspect ratio)
// 7. switch back to UV coordinate system
texturesurface_->shader()->iTransform = glm::inverse(UVtoScene) * glm::inverse(Sca) * glm::inverse(Ar) * Rot * Tra * Ar * UVtoScene;
texturesurface_->shader()->iTransform = ScenetoUV * glm::inverse(Sca) * glm::inverse(Ar) * Rot * Tra * Ar * UVtoScene;
// inform mixing group
if (mixinggroup_)
+22 -8
View File
@@ -3464,6 +3464,9 @@ void Navigator::RenderSourcePannel(Source *s, const ImVec2 &iconsize)
// index indicator
ImGui::SetCursorPos(ImVec2(pannel_width_ - 2.8f * ImGui::GetTextLineHeightWithSpacing(), IMGUI_TOP_ALIGN));
if (Mixer::manager().indexCurrentSource() < 0)
Mixer::manager().setCurrentIndex(selected_index);
ImGui::TextDisabled("#%d", Mixer::manager().indexCurrentSource());
ImGui::PopFont();
@@ -3564,17 +3567,27 @@ void Navigator::RenderSourcePannel(Source *s, const ImVec2 &iconsize)
ImGui::Text(" ");
if (s->ready() || s->failed()) {
ImVec2 size = ImVec2(ImGui::GetContentRegionAvail().x, 0);
// clone button
if ( s->failed() ) {
ImGuiToolkit::ButtonDisabled( ICON_FA_SHARE_SQUARE " Clone & Filter", ImVec2(ImGui::GetContentRegionAvail().x, 0));
}
else if ( ImGui::Button( ICON_FA_SHARE_SQUARE " Clone & Filter", ImVec2(ImGui::GetContentRegionAvail().x, 0)) ) {
if ( s->failed() )
ImGuiToolkit::ButtonDisabled( ICON_FA_SHARE_SQUARE " Clone & Filter", size);
else if ( ImGui::Button( ICON_FA_SHARE_SQUARE " Clone & Filter", size) ) {
Mixer::manager().addSource ( (Source *) Mixer::manager().createSourceClone() );
UserInterface::manager().showPannel( Mixer::manager().numSource() );
}
// bundle button
if ( s->failed() )
ImGuiToolkit::ButtonDisabled( ICON_FA_SIGN_IN_ALT " Bundle", ImVec2((size.x - IMGUI_SAME_LINE)/2.f, 0));
else if ( ImGui::Button( ICON_FA_SIGN_IN_ALT " Bundle", ImVec2((size.x - IMGUI_SAME_LINE)/2.f, 0)) ) {
Mixer::manager().groupCurrent();
UserInterface::manager().showPannel( Mixer::manager().numSource() );
}
// replace button
if ( ImGui::Button( ICON_FA_PLUS_SQUARE " Replace", ImVec2(ImGui::GetContentRegionAvail().x, 0)) ) {
ImGui::SameLine(0, IMGUI_SAME_LINE);
if ( ImGui::Button( ICON_FA_PLUS_SQUARE " Replace", ImVec2((size.x - IMGUI_SAME_LINE)/2.f, 0)) ) {
// prepare panel for new source of same type
MediaSource *file = dynamic_cast<MediaSource *>(s);
MultiFileSource *sequence = dynamic_cast<MultiFileSource *>(s);
@@ -3587,20 +3600,21 @@ void Navigator::RenderSourcePannel(Source *s, const ImVec2 &iconsize)
Settings::application.source.new_type = SOURCE_GENERATED;
else
Settings::application.source.new_type = SOURCE_CONNECTED;
// switch to panel new source
showPannelSource(NAV_NEW);
// set source to be replaced
source_to_replace = s;
}
// delete button
if ( ImGui::Button( ACTION_DELETE, ImVec2(ImGui::GetContentRegionAvail().x, 0)) ) {
if ( ImGui::Button( ACTION_DELETE, size) ) {
Mixer::manager().deleteSource(s);
Action::manager().store(sname + std::string(": Deleted"));
}
// delete all button
if ( Mixer::manager().session()->failedSources().size() > 1 ) {
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(IMGUI_COLOR_FAILED, 1.));
if ( ImGui::Button( ICON_FA_BACKSPACE " Delete all failed", ImVec2(ImGui::GetContentRegionAvail().x, 0)) ) {
if ( ImGui::Button( ICON_FA_BACKSPACE " Delete all failed", size) ) {
auto failedsources = Mixer::manager().session()->failedSources();
for (auto sit = failedsources.cbegin(); sit != failedsources.cend(); ++sit) {
Mixer::manager().deleteSource( Mixer::manager().findSource( (*sit)->id() ) );