Complete refactoring

This commit is contained in:
brunoherbelin
2020-03-22 12:22:36 +01:00
parent a435daa494
commit 0bba7a0a84
24 changed files with 929 additions and 600 deletions

View File

@@ -198,16 +198,16 @@ include_directories(
set(VMIX_BINARY "vmix")
set(VMIX_SRCS
main.cpp
ShaderManager.cpp
RenderingManager.cpp
SettingsManager.cpp
ResourceManager.cpp
UserInterfaceManager.cpp
Log.cpp
Shader.cpp
Settings.cpp
Resource.cpp
FileDialog.cpp
ImGuiToolkit.cpp
GstToolkit.cpp
MediaPlayer.cpp
Log.cpp
RenderingManager.cpp
UserInterfaceManager.cpp
)
set(VMIX_RSC_FILES
@@ -221,7 +221,7 @@ set(VMIX_RSC_FILES
./rsc/fonts/Roboto-Italic.ttf
./rsc/fonts/fa-regular-400.ttf
./rsc/fonts/fa-solid-900.ttf
./rsc/images/glmixer_256x256.png
./rsc/images/v-mix_256x256.png
./rsc/images/icons.dds
./rsc/images/seed_512.jpg
)

View File

@@ -2,17 +2,22 @@
#include <map>
#include <ctime>
#ifdef _WIN32
# include <windows.h>
# include <shellapi.h>
#endif
#include "imgui.h"
#ifndef IMGUI_DEFINE_MATH_OPERATORS
#define IMGUI_DEFINE_MATH_OPERATORS
#endif
#include "imgui_internal.h"
#define MILISECOND 1000000##L
#define SECOND 1000000000##L
#define MINUTE 60000000000##L
#define MILISECOND 1000000L
#define SECOND 1000000000L
#define MINUTE 60000000000L
#include "ResourceManager.h"
#include "Resource.h"
#include "ImGuiToolkit.h"
#include "GstToolkit.h"
@@ -30,6 +35,22 @@ std::string ImGuiToolkit::DateTime(){
return datetime;
}
void ImGuiToolkit::OpenWebpage( const char* url )
{
#ifdef _WIN32
ShellExecuteA( nullptr, nullptr, url, nullptr, nullptr, 0 );
#elif defined __APPLE__
char buf[1024];
sprintf( buf, "open %s", url );
system( buf );
#else
char buf[1024];
sprintf( buf, "xdg-open %s", url );
system( buf );
#endif
}
void ImGuiToolkit::Icon(int i, int j)
{
// icons.dds is a 20 x 20 grid of icons
@@ -68,8 +89,6 @@ void ImGuiToolkit::ShowIconsWindow(bool* p_open)
ImGui::Begin("Icons", p_open);
// ImGui::Text(" 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19");
ImVec2 pos = ImGui::GetCursorScreenPos();
ImGui::Image((void*)(intptr_t)textureicons, ImVec2(640, 640));
if (ImGui::IsItemHovered())
@@ -95,104 +114,135 @@ void ImGuiToolkit::ShowIconsWindow(bool* p_open)
ImGui::End();
}
bool ImGuiToolkit::TimelineSlider(const char* label, guint64 *time, guint64 begin, guint64 end, guint64 duration, guint64 step)
// Draws a timeline showing
// 1) a cursor at position *time in the range [0 duration]
// 2) a line of tick marks indicating time, every step if possible
// 3) a slider handle below the cursor: user can move the slider
// Behavior
// a) Returns TRUE if the left mouse button LMB is pressed over the timeline
// b) the value of *time is changed to the position of the slider handle from user input (LMB)
bool ImGuiToolkit::TimelineSlider(const char* label, guint64 *time, guint64 duration, guint64 step)
{
static guint64 optimal_tick_marks[] = { 100 * MILISECOND, 500 * MILISECOND, 1 * SECOND, 2 * SECOND, 5 * SECOND, 10 * SECOND, 20 * SECOND, 1 * MINUTE, 2 * MINUTE, 5 * MINUTE, 10 * MINUTE, 60 * MINUTE };
bool value_return = false;
static guint64 optimal_tick_marks[12] = { 100 * MILISECOND, 500 * MILISECOND, 1 * SECOND, 2 * SECOND, 5 * SECOND, 10 * SECOND, 20 * SECOND, 1 * MINUTE, 2 * MINUTE, 5 * MINUTE, 10 * MINUTE, 60 * MINUTE };
// get window
ImGuiWindow* window = ImGui::GetCurrentWindow();
if (window->SkipItems) {
return value_return;
}
if (window->SkipItems)
return false;
// get style
// get style & id
const ImGuiStyle& style = ImGui::GetStyle();
const float fontsize = ImGui::GetFontSize();
ImGuiContext& g = *GImGui;
const ImGuiID id = window->GetID(label);
//
// FIRST PREPARE ALL data structures
//
// widget bounding box
const float height = 2.f * (fontsize + style.FramePadding.y);
ImVec2 pos = window->DC.CursorPos;
ImVec2 size = ImGui::CalcItemSize(ImVec2(-FLT_MIN, 0.0f), ImGui::CalcItemWidth(), (fontsize + style.FramePadding.y)* 2.0f);
ImVec2 size = ImGui::CalcItemSize(ImVec2(-FLT_MIN, 0.0f), ImGui::CalcItemWidth(), height);
ImRect bbox(pos, pos + size);
ImGui::ItemSize(size, style.FramePadding.y);
if (!ImGui::ItemAdd(bbox, id))
return value_return;
return false;
// cursor size
const float cursor_scale = 1.f;
const float cursor_width = window->DrawList->_Data->FontSize * cursor_scale;
const float cursor_width = 0.5f * fontsize * cursor_scale;
// user input
// TIMELINE is inside the bbox, in a slightly smaller bounding box
ImRect timeline_bbox(bbox);
timeline_bbox.Expand( ImVec2(-cursor_width, -style.FramePadding.y) );
// SLIDER is inside the timeline
ImRect slider_bbox( timeline_bbox.GetTL() + ImVec2(-cursor_width + 2.f, cursor_width + 4.f ), timeline_bbox.GetBR() + ImVec2( cursor_width - 2.f, 0.f ) );
// units conversion: from time to float (calculation made with higher precision first)
float time_ = static_cast<float> ( static_cast<double>(*time) / static_cast<double>(duration) );
float step_ = static_cast<float> ( static_cast<double>(step) / static_cast<double>(duration) );
//
// SECOND GET USER INPUT AND PERFORM CHANGES AND DECISIONS
//
// read user input from system
bool left_mouse_press = false;
const bool hovered = ImGui::ItemHoverable(bbox, id);
bool temp_input_is_active = ImGui::TempInputIsActive(id);
if (!temp_input_is_active)
{
const bool focus_requested = ImGui::FocusableItemRegister(window, id);
const bool clicked = (hovered && g.IO.MouseClicked[0]);
if (focus_requested || clicked || g.NavActivateId == id || g.NavInputId == id)
left_mouse_press = hovered && ImGui::IsMouseDown(ImGuiMouseButton_Left);
if (focus_requested || left_mouse_press || g.NavActivateId == id || g.NavInputId == id)
{
ImGui::SetActiveID(id, window);
ImGui::SetFocusID(id, window);
ImGui::FocusWindow(window);
}
value_return = hovered && (clicked || g.IO.MouseDownDuration[0] > 0.f);
}
// Render bounding box
// time Slider behavior
ImRect grab_slider_bb;
ImU32 grab_slider_color = ImGui::GetColorU32(ImGuiCol_SliderGrab);
float time_slider = time_ * 10.f; // x 10 precision on grab
float time_zero = 0.f;
float time_end = 10.f;
bool value_changed = ImGui::SliderBehavior(slider_bbox, id, ImGuiDataType_Float, &time_slider, &time_zero,
&time_end, "%.2f", 1.f, ImGuiSliderFlags_None, &grab_slider_bb);
if (value_changed){
// g_print("slider %f %ld \n", time_slider, static_cast<guint64> ( static_cast<double>(time_slider) * static_cast<double>(duration) ));
*time = static_cast<guint64> ( 0.1 * static_cast<double>(time_slider) * static_cast<double>(duration) );
grab_slider_color = ImGui::GetColorU32(ImGuiCol_SliderGrabActive);
}
//
// THIRD RENDER
//
// Render the bounding box
const ImU32 frame_col = ImGui::GetColorU32(g.ActiveId == id ? ImGuiCol_FrameBgActive : g.HoveredId == id ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg);
ImGui::RenderFrame(bbox.Min, bbox.Max, frame_col, true, style.FrameRounding);
// draw inside a slightly smaller bounding box
ImRect timeline_bbox(bbox);
timeline_bbox.Expand(ImVec2(-cursor_width, 0.f));
// units conversion: from time to float (calculation made with higher precision first)
float time_ = static_cast<float> ( static_cast<double>(*time) / static_cast<double>(duration) );
float begin_ = static_cast<float> ( static_cast<double>(begin) / static_cast<double>(duration) );
float end_ = static_cast<float> ( static_cast<double>(end) / static_cast<double>(duration) );
float step_ = static_cast<float> ( static_cast<double>(step) / static_cast<double>(duration) );
// by default, put a tick mark at every frame step and a large mark every second
guint64 tick_step = step;
guint64 large_tick_step = SECOND;
// how many pixels to represent one frame step?
float tick_step_pixels = timeline_bbox.GetWidth() * step_;
float tick_step_pixels = timeline_bbox.GetWidth() * step_;
// while there is less than 3 pixels between two tick marks (or at last optimal tick mark)
for ( int i=0; i<10 && tick_step_pixels < 3.f; ++i )
{
// try to use the optimal tick marks pre-defined
tick_step = optimal_tick_marks[i];
large_tick_step = optimal_tick_marks[i+1];
tick_step_pixels = timeline_bbox.GetWidth() * static_cast<float> ( static_cast<double>(tick_step) / static_cast<double>(duration) );
}
// static guint64 t = 0;
// if (t != *time) {
// t = *time;
// ImGuiToolkit::Log("tic %ld %ld %ld %ld \n", duration, step, tick_step, large_tick_step);
// }
// tick marks along timeline
ImU32 color = ImGui::GetColorU32( style.Colors[ImGuiCol_PlotLines] );
// render the tick marks along TIMELINE
ImU32 color = ImGui::GetColorU32( style.Colors[ImGuiCol_Text] );
pos = timeline_bbox.GetTL();
guint64 tick = 0;
float tick_percent = 0.f;
while ( tick < duration)
{
// large tick mark every large tick
float tick_length = !(tick%large_tick_step) ? fontsize : style.FramePadding.y;
// draw a tick mark each step
window->DrawList->AddLine( pos, pos + ImVec2(0.f, tick_length), color);
// next tick
tick += tick_step;
float tick_percent = static_cast<float> ( static_cast<double>(tick) / static_cast<double>(duration) );
tick_percent = static_cast<float> ( static_cast<double>(tick) / static_cast<double>(duration) );
pos = ImLerp(timeline_bbox.GetTL(), timeline_bbox.GetTR(), tick_percent);
}
// end
// tick EOF
window->DrawList->AddLine( timeline_bbox.GetTR(), timeline_bbox.GetTR() + ImVec2(0.f, fontsize), color);
// render text : duration and current time
@@ -210,32 +260,222 @@ bool ImGuiToolkit::TimelineSlider(const char* label, guint64 *time, guint64 begi
if (overlay_size.x > 0.0f)
ImGui::RenderTextClipped( bbox.GetBL() + overlay_size, bbox.Max, overlay_buf, NULL, &overlay_size);
// Slider behavior
ImRect grab_bb;
ImRect slider_bbox( timeline_bbox.GetTL() + ImVec2(-cursor_width * 0.5f, cursor_width ), timeline_bbox.GetBR() + ImVec2( cursor_width * 0.5f, 0.f ) );
float time_slider = time_;
float time_zero = 0.f;
float time_end = 1.f;
bool value_changed = ImGui::SliderBehavior(slider_bbox, id, ImGuiDataType_Float, &time_slider, &time_zero,
&time_end, "%.2f", 1.f, ImGuiSliderFlags_None, &grab_bb);
if (value_changed){
// g_print("slider %f %ld \n", time_slider, static_cast<guint64> ( static_cast<double>(time_slider) * static_cast<double>(duration) ));
*time = static_cast<guint64> ( static_cast<double>(time_slider) * static_cast<double>(duration) );
// draw slider grab handle
if (grab_slider_bb.Max.x > grab_slider_bb.Min.x) {
window->DrawList->AddRectFilled(grab_slider_bb.Min, grab_slider_bb.Max, grab_slider_color, style.GrabRounding);
}
// Render grab
if (grab_bb.Max.x > grab_bb.Min.x)
window->DrawList->AddRectFilled(grab_bb.Min, grab_bb.Max,
ImGui::GetColorU32(g.ActiveId == id ? ImGuiCol_SliderGrabActive : ImGuiCol_SliderGrab),
style.GrabRounding);
// last: draw the cursor
// draw the cursor
color = ImGui::GetColorU32(style.Colors[ImGuiCol_SliderGrab]);
pos = ImLerp(timeline_bbox.GetTL(), timeline_bbox.GetTR(), time_) - ImVec2(cursor_width * 0.5f, 0.f);
pos = ImLerp(timeline_bbox.GetTL(), timeline_bbox.GetTR(), time_) - ImVec2(cursor_width, 2.f);
ImGui::RenderArrow(window->DrawList, pos, color, ImGuiDir_Up, cursor_scale);
return value_return;
return left_mouse_press;
}
// Draws a timeline showing
// 1) a cursor at position *time in the range [0 duration]
// 2) a line of tick marks indicating time, every step if possible
// 3) a slider handle below the cursor: user can move the slider
// 4) different blocs for each time segment [first second] of the list of segments
// Behavior
// a) Returns TRUE if the left mouse button LMB is pressed over the timeline
// b) the value of *time is changed to the position of the slider handle from user input (LMB)
// c) the list segments is replaced with the list of new segments created by user (empty list otherwise)
bool ImGuiToolkit::TimelineSliderEdit(const char* label, guint64 *time, guint64 duration, guint64 step,
std::list<std::pair<guint64, guint64> >& segments)
{
static guint64 optimal_tick_marks[12] = { 100 * MILISECOND, 500 * MILISECOND, 1 * SECOND, 2 * SECOND, 5 * SECOND, 10 * SECOND, 20 * SECOND, 1 * MINUTE, 2 * MINUTE, 5 * MINUTE, 10 * MINUTE, 60 * MINUTE };
// get window
ImGuiWindow* window = ImGui::GetCurrentWindow();
if (window->SkipItems)
return false;
// get style & id
const ImGuiStyle& style = ImGui::GetStyle();
const float fontsize = ImGui::GetFontSize();
ImGuiContext& g = *GImGui;
const ImGuiID id = window->GetID(label);
//
// FIRST PREPARE ALL data structures
//
// widget bounding box
const float height = 2.f * (fontsize + style.FramePadding.y);
ImVec2 pos = window->DC.CursorPos;
ImVec2 size = ImGui::CalcItemSize(ImVec2(-FLT_MIN, 0.0f), ImGui::CalcItemWidth(), height);
ImRect bbox(pos, pos + size);
ImGui::ItemSize(size, style.FramePadding.y);
if (!ImGui::ItemAdd(bbox, id))
return false;
// cursor size
const float cursor_scale = 1.f;
const float cursor_width = 0.5f * fontsize * cursor_scale;
// TIMELINE is inside the bbox, in a slightly smaller bounding box
ImRect timeline_bbox(bbox);
timeline_bbox.Expand( ImVec2(-cursor_width, -style.FramePadding.y) );
// SLIDER is inside the timeline
ImRect slider_bbox( timeline_bbox.GetTL() + ImVec2(-cursor_width + 2.f, cursor_width + 4.f ), timeline_bbox.GetBR() + ImVec2( cursor_width - 2.f, 0.f ) );
// units conversion: from time to float (calculation made with higher precision first)
float time_ = static_cast<float> ( static_cast<double>(*time) / static_cast<double>(duration) );
float step_ = static_cast<float> ( static_cast<double>(step) / static_cast<double>(duration) );
//
// SECOND GET USER INPUT AND PERFORM CHANGES AND DECISIONS
//
// read user input from system
bool left_mouse_press = false;
bool right_mouse_press = false;
const bool hovered = ImGui::ItemHoverable(bbox, id);
bool temp_input_is_active = ImGui::TempInputIsActive(id);
if (!temp_input_is_active)
{
const bool focus_requested = ImGui::FocusableItemRegister(window, id);
left_mouse_press = hovered && ImGui::IsMouseDown(ImGuiMouseButton_Left);
right_mouse_press = hovered && ImGui::IsMouseDown(ImGuiMouseButton_Right);
if (focus_requested || left_mouse_press || right_mouse_press || g.NavActivateId == id || g.NavInputId == id)
{
ImGui::SetActiveID(id, window);
ImGui::SetFocusID(id, window);
ImGui::FocusWindow(window);
}
}
// active slider if inside bb
ImRect grab_slider_bb;
ImU32 grab_slider_color = ImGui::GetColorU32(ImGuiCol_SliderGrab);
ImGuiID slider_id = window->GetID("werwerwsdvcsdgfdghdfsgagewrgsvdfhfdghkjfghsdgsdtgewfszdvgfkjfg"); // FIXME: cleaner way to create a valid but useless id that is never active
if ( slider_bbox.Contains(g.IO.MousePos) ) {
slider_id = id; // active id
grab_slider_color = ImGui::GetColorU32(ImGuiCol_SliderGrabActive);
}
// time Slider behavior
float time_slider = time_ * 10.f; // x 10 precision on grab
float time_zero = 0.f;
float time_end = 10.f;
bool value_changed = ImGui::SliderBehavior(slider_bbox, slider_id, ImGuiDataType_Float, &time_slider, &time_zero,
&time_end, "%.2f", 1.f, ImGuiSliderFlags_None, &grab_slider_bb);
if (value_changed){
// g_print("slider %f %ld \n", time_slider, static_cast<guint64> ( static_cast<double>(time_slider) * static_cast<double>(duration) ));
*time = static_cast<guint64> ( 0.1 * static_cast<double>(time_slider) * static_cast<double>(duration) );
}
// segments behavior
float time_segment_begin = 0.f;
float time_segment_end = 0.f;
if (right_mouse_press) {
time_segment_begin = 0.f;
}
//
// THIRD RENDER
//
// Render the bounding box
const ImU32 frame_col = ImGui::GetColorU32(g.ActiveId == id ? ImGuiCol_FrameBgActive : g.HoveredId == id ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg);
ImGui::RenderFrame(bbox.Min, bbox.Max, frame_col, true, style.FrameRounding);
// by default, put a tick mark at every frame step and a large mark every second
guint64 tick_step = step;
guint64 large_tick_step = SECOND;
// how many pixels to represent one frame step?
float tick_step_pixels = timeline_bbox.GetWidth() * step_;
// while there is less than 3 pixels between two tick marks (or at last optimal tick mark)
for ( int i=0; i<10 && tick_step_pixels < 3.f; ++i )
{
// try to use the optimal tick marks pre-defined
tick_step = optimal_tick_marks[i];
large_tick_step = optimal_tick_marks[i+1];
tick_step_pixels = timeline_bbox.GetWidth() * static_cast<float> ( static_cast<double>(tick_step) / static_cast<double>(duration) );
}
// render the tick marks along TIMELINE
ImU32 color_in = ImGui::GetColorU32( style.Colors[ImGuiCol_Text] );
ImU32 color_out = ImGui::GetColorU32( style.Colors[ImGuiCol_TextDisabled] );
ImU32 color = color_in;
pos = timeline_bbox.GetTL();
guint64 tick = 0;
float tick_percent = 0.f;
std::list< std::pair<guint64, guint64> >::iterator it = segments.begin();
while ( tick < duration)
{
// large tick mark every large tick
float tick_length = !(tick%large_tick_step) ? fontsize : style.FramePadding.y;
// different colors for inside and outside [begin end] of segments
if ( it != segments.end() ) {
if ( tick < it->first )
color = color_out;
else if ( tick > it->second ){
color = color_out;
it ++;
}
else
color = color_in;
}
// draw a tick mark each step
window->DrawList->AddLine( pos, pos + ImVec2(0.f, tick_length), color);
// next tick
tick += tick_step;
tick_percent = static_cast<float> ( static_cast<double>(tick) / static_cast<double>(duration) );
pos = ImLerp(timeline_bbox.GetTL(), timeline_bbox.GetTR(), tick_percent);
}
// loop over segments and EMPTY the list
// ticks for segments begin & end
for (std::list< std::pair<guint64, guint64> >::iterator s = segments.begin(); s != segments.end(); s++){
tick_percent = static_cast<float> ( static_cast<double>(s->first) / static_cast<double>(duration) );
pos = ImLerp(timeline_bbox.GetTL(), timeline_bbox.GetTR(), tick_percent);
window->DrawList->AddLine( pos, pos + ImVec2(0.f, timeline_bbox.GetHeight()), color_in);
tick_percent = static_cast<float> ( static_cast<double>(s->second) / static_cast<double>(duration) );
pos = ImLerp(timeline_bbox.GetTL(), timeline_bbox.GetTR(), tick_percent);
window->DrawList->AddLine( pos, pos + ImVec2(0.f, timeline_bbox.GetHeight()), color_in);
}
segments.clear();
// tick EOF
window->DrawList->AddLine( timeline_bbox.GetTR(), timeline_bbox.GetTR() + ImVec2(0.f, fontsize), color_in);
// render text : duration and current time
char overlay_buf[24];
ImVec2 overlay_size = ImVec2(0.f, 0.f);
ImFormatString(overlay_buf, IM_ARRAYSIZE(overlay_buf), "%s", GstToolkit::to_string(duration).c_str());
overlay_size = ImGui::CalcTextSize(overlay_buf, NULL);
overlay_size += ImVec2(3.f, 3.f);
if (overlay_size.x > 0.0f)
ImGui::RenderTextClipped( bbox.GetBR() - overlay_size, bbox.Max, overlay_buf, NULL, &overlay_size);
ImFormatString(overlay_buf, IM_ARRAYSIZE(overlay_buf), "%s", GstToolkit::to_string(*time).c_str());
overlay_size = ImGui::CalcTextSize(overlay_buf, NULL);
overlay_size = ImVec2(3.f, -3.f - overlay_size.y);
if (overlay_size.x > 0.0f)
ImGui::RenderTextClipped( bbox.GetBL() + overlay_size, bbox.Max, overlay_buf, NULL, &overlay_size);
// draw slider grab handle
if (grab_slider_bb.Max.x > grab_slider_bb.Min.x) {
window->DrawList->AddRectFilled(grab_slider_bb.Min, grab_slider_bb.Max, grab_slider_color, style.GrabRounding);
}
// draw the cursor
color = ImGui::GetColorU32(style.Colors[ImGuiCol_SliderGrab]);
pos = ImLerp(timeline_bbox.GetTL(), timeline_bbox.GetTR(), time_) - ImVec2(cursor_width, 2.f);
ImGui::RenderArrow(window->DrawList, pos, color, ImGuiDir_Up, cursor_scale);
return left_mouse_press;
}

View File

@@ -3,6 +3,8 @@
#include <glib.h>
#include <string>
#include <list>
#include <utility>
#include "rsc/fonts/IconsFontAwesome5.h"
namespace ImGuiToolkit
@@ -13,8 +15,9 @@ namespace ImGuiToolkit
void ShowIconsWindow(bool* p_open);
void ToggleButton( const char* label, bool& toggle );
void Bar(float value, float in, float out, float min, float max, const char* title, bool expand);
bool TimelineSlider(const char* label, guint64 *time,
guint64 begin, guint64 end, guint64 duration, guint64 step);
bool TimelineSlider(const char* label, guint64 *time, guint64 duration, guint64 step);
bool TimelineSliderEdit(const char* label, guint64 *time, guint64 duration, guint64 step,
std::list<std::pair<guint64, guint64> >& segments);
// fonts from ressources 'fonts/'
typedef enum {
@@ -35,6 +38,7 @@ namespace ImGuiToolkit
void SetAccentColor(accent_color color);
std::string DateTime();
};
void OpenWebpage( const char* url );
}
#endif // __IMGUI_TOOLKIT_H_

77
Log.cpp
View File

@@ -7,6 +7,14 @@
#include "imgui_internal.h"
#include "ImGuiToolkit.h"
#include "defines.h"
// multiplatform
#include <tinyfiledialogs.h>
#include <string>
#include <list>
using namespace std;
struct AppLog
{
@@ -119,7 +127,7 @@ struct AppLog
static AppLog logs;
void Log::Info(const char* fmt, ...)
void Log::Info(const char* fmt, ...)
{
va_list args;
va_start(args, fmt);
@@ -129,7 +137,72 @@ void Log::Info(const char* fmt, ...)
void Log::ShowLogWindow(bool* p_open)
{
ImGui::SetNextWindowSize(ImVec2(500, 600), ImGuiCond_FirstUseEver);
ImGui::SetNextWindowSize(ImVec2(700, 600), ImGuiCond_FirstUseEver);
logs.Draw( ICON_FA_LIST_UL " Logs", p_open);
}
static list<string> warnings;
void Log::Warning(const char* fmt, ...)
{
ImGuiTextBuffer buf;
va_list args;
va_start(args, fmt);
buf.appendfv(fmt, args);
va_end(args);
warnings.push_back(buf.c_str());
Log::Info("Warning - %s\n", buf.c_str());
}
void Log::Render()
{
if (warnings.empty())
return;
ImGuiIO& io = ImGui::GetIO();
float width = io.DisplaySize.x * 0.4f;
ImGui::OpenPopup("Warning");
if (ImGui::BeginPopupModal("Warning", NULL, ImGuiWindowFlags_AlwaysAutoResize))
{
ImGuiToolkit::Icon(9, 4);
ImGui::SameLine(0, 10);
ImGui::SetNextItemWidth(width);
ImGui::TextColored(ImVec4(1.0f,0.6f,0.0f,1.0f), "%ld error(s) occured.\n\n", warnings.size());
ImGui::Dummy(ImVec2(width, 0));
ImGui::PushTextWrapPos(ImGui::GetCursorPos().x + width);
for (list<string>::iterator it=warnings.begin(); it != warnings.end(); ++it) {
ImGui::Text("%s \n", (*it).c_str());
ImGui::Separator();
}
ImGui::PopTextWrapPos();
ImGui::Dummy(ImVec2(width * 0.8f, 0)); ImGui::SameLine(); // right align
if (ImGui::Button(" Ok ", ImVec2(width * 0.2f, 0))) {
ImGui::CloseCurrentPopup();
// messages have been seen
warnings.clear();
}
ImGui::SetItemDefaultFocus();
ImGui::EndPopup();
}
}
void Log::Error(const char* fmt, ...)
{
ImGuiTextBuffer buf;
va_list args;
va_start(args, fmt);
buf.appendfv(fmt, args);
va_end(args);
tinyfd_messageBox( APP_TITLE, buf.c_str(), "ok", "error", 0);
Log::Info("Error - %s\n", buf.c_str());
}

11
Log.h
View File

@@ -3,10 +3,15 @@
namespace Log
{
// log info
// log
void Info(const char* fmt, ...);
void Warning(const char* fmt, ...);
void Error(const char* fmt, ...);
// Draw logs
void ShowLogWindow(bool* p_open = nullptr);
};
#endif // __LOG_H_
void Render();
}
#endif // __LOG_H_

View File

@@ -1,10 +1,11 @@
#include "MediaPlayer.h"
#include <algorithm>
// vmix
#include "defines.h"
#include "Log.h"
#include "RenderingManager.h"
#include "ResourceManager.h"
#include "Resource.h"
#include "UserInterfaceManager.h"
#include "GstToolkit.h"
@@ -61,8 +62,10 @@ MediaPlayer::MediaPlayer(string name) : id(name)
loop = LoopMode::LOOP_REWIND;
need_loop = false;
v_frame_is_full = false;
current_segment = segments.begin();
textureindex = 0;
}
MediaPlayer::~MediaPlayer()
@@ -96,7 +99,7 @@ void MediaPlayer::Open(string uri)
GError *err = NULL;
discoverer = gst_discoverer_new (5 * GST_SECOND, &err);
if (!discoverer) {
UserInterface::Warning("Error creating discoverer instance: %s\n", err->message);
Log::Warning("Error creating discoverer instance: %s\n", err->message);
g_clear_error (&err);
return;
}
@@ -110,7 +113,7 @@ void MediaPlayer::Open(string uri)
gst_discoverer_start(discoverer);
// Add the request to process asynchronously the URI
if (!gst_discoverer_discover_uri_async (discoverer, uri.c_str())) {
UserInterface::Warning("Failed to start discovering URI '%s'\n", uri.c_str());
Log::Warning("Failed to start discovering URI '%s'\n", uri.c_str());
g_object_unref (discoverer);
discoverer = nullptr;
}
@@ -129,7 +132,7 @@ void MediaPlayer::execute_open()
GError *error = NULL;
pipeline = gst_parse_launch (description.c_str(), &error);
if (error != NULL) {
UserInterface::Warning("Could not construct pipeline %s:\n%s\n", description.c_str(), error->message);
Log::Warning("Could not construct pipeline %s:\n%s\n", description.c_str(), error->message);
g_clear_error (&error);
return;
}
@@ -139,7 +142,7 @@ void MediaPlayer::execute_open()
string capstring = "video/x-raw,format=RGB,width="+ std::to_string(width) + ",height=" + std::to_string(height);
GstCaps *caps = gst_caps_from_string(capstring.c_str());
if (!gst_video_info_from_caps (&v_frame_video_info, caps)) {
UserInterface::Warning("%s: Could not configure MediaPlayer video frame info\n", gst_element_get_name(pipeline));
Log::Warning("%s: Could not configure MediaPlayer video frame info\n", gst_element_get_name(pipeline));
return;
}
@@ -164,7 +167,7 @@ void MediaPlayer::execute_open()
gst_object_unref (sink);
}
else {
UserInterface::Warning("%s: Could not configure MediaPlayer sink\n", gst_element_get_name(pipeline));
Log::Warning("%s: Could not configure MediaPlayer sink\n", gst_element_get_name(pipeline));
return;
}
gst_caps_unref (caps);
@@ -175,7 +178,7 @@ void MediaPlayer::execute_open()
// set to desired state (PLAY or PAUSE)
GstStateChangeReturn ret = gst_element_set_state (pipeline, desired_state);
if (ret == GST_STATE_CHANGE_FAILURE) {
UserInterface::Warning("%s: Failed to open media %s \n%s\n", gst_element_get_name(pipeline), uri.c_str(), discoverer_message.str().c_str());
Log::Warning("%s: Failed to open media %s \n%s\n", gst_element_get_name(pipeline), uri.c_str(), discoverer_message.str().c_str());
}
else {
// all good
@@ -290,7 +293,7 @@ void MediaPlayer::Play(bool on)
// all ready, apply state change immediately
GstStateChangeReturn ret = gst_element_set_state (pipeline, desired_state);
if (ret == GST_STATE_CHANGE_FAILURE) {
UserInterface::Warning("Failed to start up Media %s\n", gst_element_get_name(pipeline));
Log::Warning("Failed to start up Media %s\n", gst_element_get_name(pipeline));
}
#ifdef MEDIA_PLAYER_DEBUG
else if (on)
@@ -394,6 +397,47 @@ void MediaPlayer::FastForward()
}
bool MediaPlayer::addPlaySegment(GstClockTime begin, GstClockTime end)
{
return addPlaySegment( MediaSegment(begin, end) );
}
bool MediaPlayer::addPlaySegment(MediaSegment s)
{
if ( s.is_valid() )
return segments.insert(s).second;
return false;
}
bool MediaPlayer::removeAllPlaySegmentOverlap(MediaSegment s)
{
bool ret = removePlaySegmentAt(s.begin);
return removePlaySegmentAt(s.end) || ret;
}
bool MediaPlayer::removePlaySegmentAt(GstClockTime t)
{
MediaSegmentSet::const_iterator s = std::find_if(segments.begin(), segments.end(), containsTime(t));
if ( s != segments.end() ) {
segments.erase(s);
return true;
}
return false;
}
std::list< std::pair<guint64, guint64> > MediaPlayer::getPlaySegments() const
{
std::list< std::pair<guint64, guint64> > ret;
for (MediaSegmentSet::iterator it = segments.begin(); it != segments.end(); it++)
ret.push_back( std::make_pair( it->begin, it->end ) );
return ret;
}
void MediaPlayer::Update()
{
// discard
@@ -408,6 +452,7 @@ void MediaPlayer::Update()
// apply texture
if (v_frame_is_full) {
// first occurence; create texture
if (textureindex==0) {
glActiveTexture(GL_TEXTURE0);
glGenTextures(1, &textureindex);
@@ -417,7 +462,7 @@ void MediaPlayer::Update()
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height,
0, GL_RGB, GL_UNSIGNED_BYTE, v_frame.data[0]);
}
else
else // bind texture
{
glBindTexture(GL_TEXTURE_2D, textureindex);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height,
@@ -430,20 +475,34 @@ void MediaPlayer::Update()
// manage loop mode
if (need_loop && !isimage) {
if (loop == LOOP_NONE)
Play(false);
else
execute_loop_command();
execute_loop_command();
need_loop = false;
}
// all other updates below are only for playing mode
if (desired_state != GST_STATE_PLAYING)
return;
// test segments
if ( segments.begin() != segments.end()) {
if ( current_segment == segments.end() )
current_segment = segments.begin();
if ( Position() > current_segment->end) {
g_print("switch to next segment ");
current_segment++;
if ( current_segment == segments.end() )
current_segment = segments.begin();
SeekTo(current_segment->begin);
}
}
}
void MediaPlayer::execute_loop_command()
{
if ( pipeline == nullptr) return;
if (loop==LOOP_REWIND) {
Rewind();
}
@@ -451,7 +510,9 @@ void MediaPlayer::execute_loop_command()
rate *= - 1.f;
execute_seek_command();
}
else {
Play(false);
}
}
void MediaPlayer::execute_seek_command(GstClockTime target)
@@ -481,7 +542,7 @@ void MediaPlayer::execute_seek_command(GstClockTime target)
int seek_flags = GST_SEEK_FLAG_FLUSH;
// seek with trick mode if fast speed
if ( ABS(rate) > 2.0 )
seek_flags |= GST_SEEK_FLAG_TRICKMODE | GST_SEEK_FLAG_TRICKMODE_NO_AUDIO;
seek_flags |= GST_SEEK_FLAG_TRICKMODE;
// create seek event depending on direction
if (rate > 0) {
@@ -492,7 +553,7 @@ void MediaPlayer::execute_seek_command(GstClockTime target)
GST_SEEK_TYPE_SET, 0, GST_SEEK_TYPE_SET, seek_pos);
}
// Send the event
// Send the event (ASYNC)
if (seek_event && !gst_element_send_event(pipeline, seek_event) )
Log::Info("Seek failed in Media %s\n", gst_element_get_name(pipeline));
#ifdef MEDIA_PLAYER_DEBUG
@@ -532,6 +593,7 @@ double MediaPlayer::UpdateFrameRate() const
return timecount.framerate();
}
// CALLBACKS
bool MediaPlayer::fill_v_frame(GstBuffer *buf)
@@ -690,7 +752,7 @@ TimeCounter::TimeCounter() {
current_time = gst_util_get_timestamp ();
last_time = gst_util_get_timestamp();
nbFrames = 0;
fps = 0.f;
fps = 1.f;
}
void TimeCounter::tic ()
@@ -700,7 +762,7 @@ void TimeCounter::tic ()
if ((current_time - last_time) >= GST_SECOND)
{
last_time = current_time;
fps = 0.2f * fps + 0.8f * static_cast<float>(nbFrames);
fps = 0.1f * fps + 0.9f * static_cast<float>(nbFrames);
nbFrames = 0;
}
}

View File

@@ -4,6 +4,9 @@
#include <string>
#include <atomic>
#include <sstream>
#include <set>
#include <list>
#include <utility>
using namespace std;
#include <gst/gst.h>
@@ -26,18 +29,71 @@ public:
int framecount() const;
};
struct MediaSegment
{
GstClockTime begin;
GstClockTime end;
MediaSegment()
{
begin = GST_CLOCK_TIME_NONE;
end = GST_CLOCK_TIME_NONE;
}
MediaSegment(GstClockTime b, GstClockTime e)
{
if ( b < e ) {
begin = b;
end = e;
} else {
begin = GST_CLOCK_TIME_NONE;
end = GST_CLOCK_TIME_NONE;
}
}
inline bool is_valid() const
{
return begin != GST_CLOCK_TIME_NONE && end != GST_CLOCK_TIME_NONE && begin < end;
}
inline bool operator < (const MediaSegment b) const
{
return (this->is_valid() && b.is_valid() && this->end < b.begin);
}
inline bool operator == (const MediaSegment b) const
{
return (this->begin == b.begin && this->end == b.end);
}
inline bool operator != (const MediaSegment b) const
{
return (this->begin != b.begin || this->end != b.end);
}
};
struct containsTime: public std::unary_function<MediaSegment, bool>
{
inline bool operator()(const MediaSegment s) const
{
return ( s.is_valid() && _t > s.begin && _t < s.end );
}
containsTime(GstClockTime t) : _t(t) { }
private:
GstClockTime _t;
};
typedef std::set<MediaSegment> MediaSegmentSet;
class MediaPlayer {
public:
/**
* Constructor of a GStreamer Media
*
*/
MediaPlayer(string name);
/**
* Destructor.
*
*/
~MediaPlayer();
/**
@@ -141,8 +197,16 @@ public:
guint Height() const;
float AspectRatio() const;
private:
bool addPlaySegment(GstClockTime begin, GstClockTime end);
bool addPlaySegment(MediaSegment s);
bool removePlaySegmentAt(GstClockTime t);
bool removeAllPlaySegmentOverlap(MediaSegment s);
std::list< std::pair<guint64, guint64> > getPlaySegments() const;
string id;
string uri;
guint textureindex;
@@ -165,13 +229,16 @@ private:
std::atomic<bool> v_frame_is_full;
std::atomic<bool> need_loop;
MediaSegmentSet segments;
MediaSegmentSet::iterator current_segment;
bool ready;
bool seekable;
bool isimage;
void execute_open();
void execute_loop_command();
void execute_seek_command(GstClockTime target = GST_CLOCK_TIME_NONE);
void execute_seek_command(GstClockTime target = GST_CLOCK_TIME_NONE);
bool fill_v_frame(GstBuffer *buf);
static GstFlowReturn callback_pull_sample_video (GstElement *bin, MediaPlayer *m);

View File

@@ -42,51 +42,40 @@
// vmix
#include "defines.h"
#include "Log.h"
#include "ResourceManager.h"
#include "SettingsManager.h"
#include "Resource.h"
#include "Settings.h"
#include "UserInterfaceManager.h"
#include "RenderingManager.h"
// Class statics
GLFWwindow* Rendering::window = nullptr;
std::string Rendering::glsl_version;
int Rendering::render_width = 0;
int Rendering::render_height = 0;
std::list<Rendering::RenderingCallback> Rendering::drawCallbacks;
Screenshot Rendering::window_screenshot;
bool Rendering::request_screenshot = false;
// local statics
static GstGLContext *global_gl_context = NULL;
static GstGLDisplay *global_display = NULL;
static guintptr global_window_handle = 0;
static void glfw_error_callback(int error, const char* description)
{
std::string msg = "Glfw Error: " + std::string(description);
UserInterface::Error(msg, APP_TITLE);
Log::Error("Glfw Error %d: %s", error, description);
}
static void WindowRefreshCallback( GLFWwindow* window )
{
Rendering::Draw();
Rendering::manager().Draw();
}
glm::mat4 Rendering::Projection() {
glm::mat4 projection = glm::ortho(-5.0, 5.0, -5.0, 5.0);
glm::mat4 scale = glm::scale(glm::mat4(1.0f), glm::vec3(1.f, AspectRatio(), 1.f));
return projection * scale;
Rendering::Rendering()
{
window = nullptr;
render_width = 0;
render_height = 0;
request_screenshot = false;
}
bool Rendering::Init()
{
// Setup window
glfwSetErrorCallback(glfw_error_callback);
if (!glfwInit()){
UserInterface::Error("Failed to Initialize GLFW.");
Log::Error("Failed to Initialize GLFW.");
return false;
}
@@ -99,19 +88,19 @@ bool Rendering::Init()
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // Required on Mac
#endif
WindowSettings winset = Settings::application.windows.front();
Settings::Window winset = Settings::application.windows.front();
// Create window with graphics context
glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE);
window = glfwCreateWindow(winset.w, winset.h, winset.name.c_str(), NULL, NULL);
if (window == NULL){
UserInterface::Error("Failed to Create GLFW Window.");
Log::Error("Failed to Create GLFW Window.");
return false;
}
// Add application icon
size_t fpsize = 0;
const char *fp = Resource::getData("images/glmixer_256x256.png", &fpsize);
const char *fp = Resource::getData("images/v-mix_256x256.png", &fpsize);
if (fp != nullptr) {
GLFWimage icon;
icon.pixels = stbi_load_from_memory( (const stbi_uc*)fp, fpsize, &icon.width, &icon.height, nullptr, 4 );
@@ -127,7 +116,7 @@ bool Rendering::Init()
// Initialize OpenGL loader
bool err = gladLoadGLLoader((GLADloadproc) glfwGetProcAddress) == 0;
if (err) {
UserInterface::Error("Failed to initialize OpenGL loader.");
Log::Error("Failed to initialize GLAD OpenGL loader.");
return false;
}
@@ -146,50 +135,19 @@ bool Rendering::Init()
gst_init (NULL, NULL);
#if GST_GL_HAVE_PLATFORM_WGL
context =
gst_gl_context_new_wrapped (display, (guintptr) wglGetCurrentContext (),
GST_GL_PLATFORM_WGL, GST_GL_API_OPENGL);
global_gl_context = gst_gl_context_new_wrapped (display, (guintptr) wglGetCurrentContext (),
GST_GL_PLATFORM_WGL, GST_GL_API_OPENGL);
#elif GST_GL_HAVE_PLATFORM_CGL
// GstGLDisplay* display = gst_gl_display_new();
// guintptr context = gst_gl_context_get_current_gl_context(GST_GL_HAVE_PLATFORM_CGL);
// GstGLContext* gstcontext = gst_gl_context_new_wrapped(display, context, GST_GL_HAVE_PLATFORM_CGL, GST_GL_API_OPENGL);
// GstGLDisplay *gst_display;
// global_display = GST_GL_DISPLAY ( glfwGetCocoaMonitor(window) );
// global_display = GST_GL_DISPLAY (gst_gl_display_cocoa_new ());
// GstGLDisplay *gst_display;
// global_gl_context = gst_gl_context_new_wrapped (global_display,
// (guintptr) 0,
// GST_GL_PLATFORM_CGL, GST_GL_API_OPENGL);
//global_display = GST_GL_DISPLAY ( glfwGetCocoaMonitor(window) );
//GstGLDisplayCocoa *tmp = gst_gl_display_cocoa_new ();
global_display = GST_GL_DISPLAY (gst_gl_display_cocoa_new ());
//glfwMakeContextCurrent(window);
global_gl_context = gst_gl_context_new_wrapped (global_display,
(guintptr) 0,
GST_GL_PLATFORM_CGL, GST_GL_API_OPENGL);
// id toto = glfwGetNSGLContext(window);
// g_warning("OpenGL Contexts %ld %ld", (long int) glfwGetNSGLContext(window), (long int) CocoaToolkit::get_current_nsopengl_context() );
// global_gl_context = gst_gl_context_new_wrapped (global_display,
// (guintptr) glfwGetNSGLContext(window),
// GST_GL_PLATFORM_CGL, GST_GL_API_OPENGL);
// guintptr context;
// context = gst_gl_context_get_current_gl_context (GST_GL_PLATFORM_CGL);
// gst_display = gst_gl_display_new ();
// global_gl_context = gst_gl_context_new_wrapped (GST_GL_DISPLAY (gst_display),
// context, GST_GL_PLATFORM_CGL, gst_gl_context_get_current_gl_api (GST_GL_PLATFORM_CGL, NULL, NULL));
// global_display = GST_GL_DISPLAY ( gst_gl_context_get_display(global_gl_context) );
// global_window_handle = (guintptr) glfwGetCocoaWindow(window);
#elif GST_GL_HAVE_PLATFORM_GLX
@@ -237,9 +195,9 @@ void Rendering::AddDrawCallback(RenderingCallback function)
void Rendering::Draw()
{
if (Rendering::Begin() )
if ( Begin() )
{
UserInterface::NewFrame();
UserInterface::manager().NewFrame();
std::list<Rendering::RenderingCallback>::iterator iter;
for (iter=drawCallbacks.begin(); iter != drawCallbacks.end(); iter++)
@@ -247,8 +205,8 @@ void Rendering::Draw()
(*iter)();
}
UserInterface::Render();
Rendering::End();
UserInterface::manager().Render();
End();
}
// no g_main_loop_run(loop) : update global GMainContext
@@ -324,6 +282,14 @@ void Rendering::Close()
glfwSetWindowShouldClose(window, true);
}
glm::mat4 Rendering::Projection() {
glm::mat4 projection = glm::ortho(-5.0, 5.0, -5.0, 5.0);
glm::mat4 scale = glm::scale(glm::mat4(1.0f), glm::vec3(1.f, AspectRatio(), 1.f));
return projection * scale;
}
void Rendering::ToggleFullscreen()
{
// if in fullscreen mode
@@ -362,52 +328,6 @@ float Rendering::AspectRatio()
return static_cast<float>(render_width) / static_cast<float>(render_height);
}
static GstBusSyncReply
bus_sync_handler (GstBus * bus, GstMessage * msg, gpointer user_data)
{
if (GST_MESSAGE_TYPE(msg) == GST_MESSAGE_NEED_CONTEXT) {
const gchar* contextType;
gst_message_parse_context_type(msg, &contextType);
if (!g_strcmp0(contextType, GST_GL_DISPLAY_CONTEXT_TYPE)) {
GstContext *displayContext = gst_context_new(GST_GL_DISPLAY_CONTEXT_TYPE, TRUE);
gst_context_set_gl_display(displayContext, global_display);
gst_element_set_context(GST_ELEMENT(msg->src), displayContext);
gst_context_unref (displayContext);
g_info ("Managed %s\n", contextType);
}
if (!g_strcmp0(contextType, "gst.gl.app_context")) {
GstContext *appContext = gst_context_new("gst.gl.app_context", TRUE);
GstStructure* structure = gst_context_writable_structure(appContext);
gst_structure_set(structure, "context", GST_TYPE_GL_CONTEXT, global_gl_context, nullptr);
gst_element_set_context(GST_ELEMENT(msg->src), appContext);
gst_context_unref (appContext);
g_info ("Managed %s\n", contextType);
}
}
gst_message_unref (msg);
return GST_BUS_DROP;
}
void Rendering::LinkPipeline( GstPipeline *pipeline )
{
// capture bus signals to force a unique opengl context for all GST elements
GstBus* m_bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
gst_bus_set_sync_handler (m_bus, (GstBusSyncHandler) bus_sync_handler, pipeline, NULL);
gst_object_unref (m_bus);
// GstBus* m_bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
// gst_bus_enable_sync_message_emission (m_bus);
// g_signal_connect (m_bus, "sync-message", G_CALLBACK (bus_sync_handler), pipeline);
// gst_object_unref (m_bus);
}
void Rendering::FileDropped(GLFWwindow* window, int path_count, const char* paths[])
{
for (int i = 0; i < path_count; ++i) {
@@ -502,3 +422,57 @@ void Screenshot::FlipVertical()
}
delete[] line_tmp;
}
//
// Discarded because not working under OSX - kept in case it would become useful
//
// Linking pipeline to the rendering instance ensures the opengl contexts
// created by gstreamer inside plugins (e.g. glsinkbin) is the same
//
static GstBusSyncReply
bus_sync_handler (GstBus * bus, GstMessage * msg, gpointer user_data)
{
if (GST_MESSAGE_TYPE(msg) == GST_MESSAGE_NEED_CONTEXT) {
const gchar* contextType;
gst_message_parse_context_type(msg, &contextType);
if (!g_strcmp0(contextType, GST_GL_DISPLAY_CONTEXT_TYPE)) {
GstContext *displayContext = gst_context_new(GST_GL_DISPLAY_CONTEXT_TYPE, TRUE);
gst_context_set_gl_display(displayContext, global_display);
gst_element_set_context(GST_ELEMENT(msg->src), displayContext);
gst_context_unref (displayContext);
g_info ("Managed %s\n", contextType);
}
if (!g_strcmp0(contextType, "gst.gl.app_context")) {
GstContext *appContext = gst_context_new("gst.gl.app_context", TRUE);
GstStructure* structure = gst_context_writable_structure(appContext);
gst_structure_set(structure, "context", GST_TYPE_GL_CONTEXT, global_gl_context, nullptr);
gst_element_set_context(GST_ELEMENT(msg->src), appContext);
gst_context_unref (appContext);
g_info ("Managed %s\n", contextType);
}
}
gst_message_unref (msg);
return GST_BUS_DROP;
}
void Rendering::LinkPipeline( GstPipeline *pipeline )
{
// capture bus signals to force a unique opengl context for all GST elements
GstBus* m_bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
gst_bus_set_sync_handler (m_bus, (GstBusSyncHandler) bus_sync_handler, pipeline, NULL);
gst_object_unref (m_bus);
// GstBus* m_bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
// gst_bus_enable_sync_message_emission (m_bus);
// g_signal_connect (m_bus, "sync-message", G_CALLBACK (bus_sync_handler), pipeline);
// gst_object_unref (m_bus);
}

View File

@@ -34,56 +34,70 @@ class Rendering
friend class UserInterface;
// GLFW integration in OS window management
static class GLFWwindow* window;
static Screenshot window_screenshot;
static std::string glsl_version;
static int render_width, render_height;
static bool request_screenshot;
class GLFWwindow* window;
Screenshot window_screenshot;
std::string glsl_version;
int render_width, render_height;
bool request_screenshot;
// Private Constructor
Rendering();
Rendering(Rendering const& copy); // Not Implemented
Rendering& operator=(Rendering const& copy); // Not Implemented
public:
// Initialization OpenGL and GLFW window creation
static bool Init();
// true if active rendering window
static bool isActive();
// request close of the UI (Quit the program)
static void Close();
// Post-loop termination
static void Terminate();
static Rendering& manager()
{
// The only instance
static Rendering _instance;
return _instance;
}
// Initialization OpenGL and GLFW window creation
bool Init();
// true if active rendering window
bool isActive();
// draw one frame
static void Draw();
void Draw();
// request close of the UI (Quit the program)
void Close();
// Post-loop termination
void Terminate();
// add function to call during Draw
typedef void (* RenderingCallback)(void);
static void AddDrawCallback(RenderingCallback function);
void AddDrawCallback(RenderingCallback function);
// request screenshot
static void RequestScreenshot();
void RequestScreenshot();
// get Screenshot
static Screenshot *CurrentScreenshot();
Screenshot *CurrentScreenshot();
// request fullscreen
static void ToggleFullscreen();
void ToggleFullscreen();
// get width of rendering area
static float Width() { return render_width; }
float Width() { return render_width; }
// get height of rendering area
static float Height() { return render_height; }
float Height() { return render_height; }
// get aspect ratio of rendering area
static float AspectRatio();
// get projection matrix (for sharers)
static glm::mat4 Projection();
float AspectRatio();
// for opengl pipile in gstreamer
static void LinkPipeline( GstPipeline *pipeline );
// get projection matrix (for sharers) => Views
glm::mat4 Projection();
// for opengl pipeline in gstreamer
void LinkPipeline( GstPipeline *pipeline );
private:
// loop update to begin new frame
static bool Begin();
bool Begin();
// loop update end frame
static void End();
void End();
// list of functions to call at each Draw
static std::list<RenderingCallback> drawCallbacks;
std::list<RenderingCallback> drawCallbacks;
// file drop callback
static void FileDropped(GLFWwindow* window, int path_count, const char* paths[]);

View File

@@ -1,5 +1,5 @@
#include "defines.h"
#include "ResourceManager.h"
#include "Resource.h"
#include "Log.h"
#include <fstream>
@@ -21,7 +21,7 @@
CMRC_DECLARE(vmix);
std::map<std::string, unsigned int> Resource::textureIndex;
std::map<std::string, unsigned int> textureIndex;
const char *Resource::getData(const std::string& path, size_t* out_file_size){
@@ -202,7 +202,7 @@ unsigned int Resource::getTextureImage(const std::string& path)
return textureID;
}
void Resource::listFiles()
std::string Resource::listDirectory()
{
// enter icons directory
auto fs = cmrc::vmix::get_filesystem();
@@ -210,16 +210,19 @@ void Resource::listFiles()
cmrc::directory_iterator it = fs.iterate_directory("");
cmrc::directory_iterator itend = it.end();
std::string ls;
// loop over all icons
while(it != itend){
cmrc::directory_entry file = *it;
if (file.is_file()) {
std::cerr << "Found file " << file.filename() << std::endl;
ls += file.filename() + ", ";
}
it++;
}
return ls;
}

30
Resource.h Normal file
View File

@@ -0,0 +1,30 @@
#ifndef __RSC_MANAGER_H_
#define __RSC_MANAGER_H_
#include <string>
#include <map>
namespace Resource
{
// Support all text files
// return file tyext content as one string
std::string getText(const std::string& path);
// Support DDS files, DXT1, DXT5 and DXT5
// Returns the OpenGL generated Texture index
unsigned int getTextureDDS(const std::string& path);
// Support PNG, JPEG, TGA, BMP, PSD, GIF, HDR, PIC, PNM
// Returns the OpenGL generated Texture index
unsigned int getTextureImage(const std::string& path);
// Generic access to pointer to data
const char *getData(const std::string& path, size_t* out_file_size);
// list files in resource directory
std::string listDirectory();
}
#endif /* __RSC_MANAGER_H_ */

View File

@@ -1,33 +0,0 @@
#ifndef vlmixer_rsc_manager
#define vlmixer_rsc_manager
#include <string>
#include <map>
class Resource
{
static std::map<std::string, unsigned int> textureIndex;
static void listFiles();
public:
// Support all text files
// return file tyext content as one string
static std::string getText(const std::string& path);
// Support DDS files, DXT1, DXT5 and DXT5
// Returns the OpenGL generated Texture index
static unsigned int getTextureDDS(const std::string& path);
// Support PNG, JPEG, TGA, BMP, PSD, GIF, HDR, PIC, PNM
// Returns the OpenGL generated Texture index
static unsigned int getTextureImage(const std::string& path);
// Generic access to pointer to data
static const char *getData(const std::string& path, size_t* out_file_size);
};
#endif /* vlmixer_rsc_manager */

View File

@@ -1,5 +1,5 @@
#include "SettingsManager.h"
#include "defines.h"
#include "Settings.h"
#include "Log.h"
#include <iostream>
@@ -7,20 +7,12 @@
using namespace tinyxml2;
#ifndef XMLCheckResult
#define XMLCheckResult(a_eResult) if (a_eResult != XML_SUCCESS) { printf("Settings warning: %i\n", a_eResult); return; }
#define XMLCheckResult(a_eResult) if (a_eResult != XML_SUCCESS) { Log::Warning("XML error %i\n", a_eResult); return; }
#endif
AppSettings Settings::application(APP_NAME);
AppSettings::AppSettings(const string& name) {
this->name = name;
this->filename = "./" + name + ".xml";
this->windows.clear();
this->windows.push_back(WindowSettings(15,15,1280,720, APP_TITLE));
this->scale = 1.0;
this->color = 0;
}
Settings::Application Settings::application;
string filename = string("./") + APP_NAME + ".xml";
void Settings::Save()
{
@@ -41,10 +33,10 @@ void Settings::Save()
{
XMLElement *windowsNode = xmlDoc.NewElement( "Windows" );
list<WindowSettings>::iterator iter;
list<Settings::Window>::iterator iter;
for (iter=application.windows.begin(); iter != application.windows.end(); iter++)
{
const WindowSettings& w=*iter;
const Settings::Window& w=*iter;
XMLElement *window = xmlDoc.NewElement( "Window" );
window->SetAttribute("name", w.name.c_str());
@@ -64,14 +56,14 @@ void Settings::Save()
applicationNode->SetAttribute("color", application.color);
pRoot->InsertEndChild(applicationNode);
XMLError eResult = xmlDoc.SaveFile(application.filename.c_str());
XMLError eResult = xmlDoc.SaveFile(filename.c_str());
XMLCheckResult(eResult);
}
void Settings::Load()
{
XMLDocument xmlDoc;
XMLError eResult = xmlDoc.LoadFile(application.filename.c_str());
XMLError eResult = xmlDoc.LoadFile(filename.c_str());
// do not warn if non existing file
if (eResult == XML_ERROR_FILE_NOT_FOUND)
@@ -96,7 +88,7 @@ void Settings::Load()
XMLElement* pWindowNode = pElement->FirstChildElement("Window");
for( ; pWindowNode ; pWindowNode=pWindowNode->NextSiblingElement())
{
WindowSettings w;
Settings::Window w;
const char *pName=pWindowNode->Attribute("name");
if (pName) w.name=pName;
@@ -123,8 +115,8 @@ void Settings::Check()
Settings::Save();
XMLDocument xmlDoc;
XMLError eResult = xmlDoc.LoadFile(application.filename.c_str());
XMLError eResult = xmlDoc.LoadFile(filename.c_str());
XMLCheckResult(eResult);
xmlDoc.Print();
}
}

47
Settings.h Normal file
View File

@@ -0,0 +1,47 @@
#ifndef __SETTINGS_H_
#define __SETTINGS_H_
#include "defines.h"
#include <string>
#include <list>
using namespace std;
namespace Settings {
struct Window
{
string name;
int x,y,w,h;
bool fullscreen;
Window() : name(APP_TITLE), x(15), y(15), w(1280), h(720), fullscreen(false) { }
};
struct Application
{
string name;
float scale;
int color;
list<Window> windows;
Application() : name(APP_NAME), scale(1.f), color(0){
windows.push_back(Window());
}
};
// minimal implementation of settings
// Can be accessed r&w anywhere
extern Application application;
// Save and Load store settings in XML file
void Save();
void Load();
void Check();
}
#endif /* __SETTINGS_H_ */

View File

@@ -1,52 +0,0 @@
#ifndef vlmixer_app_settings
#define vlmixer_app_settings
#include <string>
#include <list>
using namespace std;
class WindowSettings
{
public:
int x,y,w,h;
string name;
bool fullscreen;
WindowSettings() : x(0), y(0), w(100), h(100), name("Untitled"), fullscreen(false)
{
}
WindowSettings(int x, int y, int w, int h, const string& name)
{
this->x=x;
this->y=y;
this->w=w;
this->h=h;
this->name=name;
this->fullscreen=false;
}
};
class AppSettings
{
public:
string name;
string filename;
list<WindowSettings> windows;
float scale;
int color;
AppSettings(const string& name);
};
class Settings
{
public:
static AppSettings application;
static void Save();
static void Load();
static void Check();
};
#endif /* vlmixer_app_settings */

View File

@@ -1,5 +1,5 @@
#include "ShaderManager.h"
#include "ResourceManager.h"
#include "Shader.h"
#include "Resource.h"
#include <fstream>
#include <sstream>

View File

@@ -25,27 +25,17 @@
#define STB_IMAGE_WRITE_IMPLEMENTATION
#include <stb_image_write.h>
#ifdef _WIN32
# include <windows.h>
# include <shellapi.h>
#endif
#include "defines.h"
#include "Log.h"
#include "TextEditor.h"
#include "UserInterfaceManager.h"
#include "RenderingManager.h"
#include "ResourceManager.h"
#include "SettingsManager.h"
#include "Resource.h"
#include "Settings.h"
#include "FileDialog.h"
#include "ImGuiToolkit.h"
#include "GstToolkit.h"
MessageBox UserInterface::warnings;
MainWindow UserInterface::mainwindow;
std::string UserInterface::currentFileDialog = "";
std::string UserInterface::currentTextEdit = "";
static std::thread loadThread;
static bool loadThreadDone = false;
static TextEditor editor;
@@ -74,25 +64,16 @@ static void NativeOpenFile(std::string ext)
}
static void OpenWebpage( const char* url )
{
#ifdef _WIN32
ShellExecuteA( nullptr, nullptr, url, nullptr, nullptr, 0 );
#elif defined __APPLE__
char buf[1024];
sprintf( buf, "open %s", url );
system( buf );
#else
char buf[1024];
sprintf( buf, "xdg-open %s", url );
system( buf );
#endif
}
UserInterface::UserInterface()
{
currentFileDialog = "";
currentTextEdit = "";
}
bool UserInterface::Init()
{
if (Rendering::window == nullptr)
if (Rendering::manager().window == nullptr)
return false;
// Setup Dear ImGui context
@@ -103,8 +84,8 @@ bool UserInterface::Init()
io.MouseDrawCursor = true;
// Setup Platform/Renderer bindings
ImGui_ImplGlfw_InitForOpenGL(Rendering::window, true);
ImGui_ImplOpenGL3_Init(Rendering::glsl_version.c_str());
ImGui_ImplGlfw_InitForOpenGL(Rendering::manager().window, true);
ImGui_ImplOpenGL3_Init(Rendering::manager().glsl_version.c_str());
// Setup Dear ImGui style
ImGuiToolkit::SetAccentColor(static_cast<ImGuiToolkit::accent_color>(Settings::application.color));
@@ -148,7 +129,7 @@ void UserInterface::handleKeyboard()
if ( io.KeyCtrl ) {
if (ImGui::IsKeyPressed( GLFW_KEY_Q ))
Rendering::Close();
Rendering::manager().Close();
else if (ImGui::IsKeyPressed( GLFW_KEY_O ))
UserInterface::OpenFileMedia();
else if (ImGui::IsKeyPressed( GLFW_KEY_S ))
@@ -162,7 +143,7 @@ void UserInterface::handleKeyboard()
// Application F-Keys
if (ImGui::IsKeyPressed( GLFW_KEY_F12 ))
Rendering::ToggleFullscreen();
Rendering::manager().ToggleFullscreen();
else if (ImGui::IsKeyPressed( GLFW_KEY_F11 ))
mainwindow.StartScreenshot();
@@ -205,17 +186,17 @@ void UserInterface::NewFrame()
ImGui_ImplGlfw_NewFrame();
ImGui::NewFrame();
// Main window
mainwindow.Render();
}
void UserInterface::Render()
{
ImVec2 geometry(static_cast<float>(Rendering::render_width), static_cast<float>(Rendering::render_height));
ImVec2 geometry(static_cast<float>(Rendering::manager().Width()), static_cast<float>(Rendering::manager().Height()));
// Main window
mainwindow.Render();
// warning modal dialog
warnings.Render( geometry.x * 0.4f ); // 40% width
Log::Render();
// file modal dialog
geometry.x *= 0.4f;
@@ -242,62 +223,6 @@ void UserInterface::Terminate()
ImGui::DestroyContext();
}
void UserInterface::Error(const string& text, const string& title)
{
// Show NON Graphical dialog (using multiplatform tiny file dialog )
string t = title.empty() ? APP_TITLE : title;
tinyfd_messageBox( t.c_str(), text.c_str(), "ok", "error", 0);
}
void UserInterface::Warning(const char* fmt, ...)
{
va_list args;
va_start(args, fmt);
ImGuiTextBuffer buf;
buf.appendfv(fmt, args);
warnings.messages.push_back(buf.c_str());
Log::Info(buf.c_str());
va_end(args);
}
MessageBox::MessageBox()
{
}
void MessageBox::Render(float width)
{
if (messages.empty())
return;
ImGui::OpenPopup("Warning");
if (ImGui::BeginPopupModal("Warning", NULL, ImGuiWindowFlags_AlwaysAutoResize))
{
ImGuiToolkit::Icon(9, 4);
ImGui::SameLine(0, 10);
ImGui::TextColored(ImVec4(1.0f,0.6f,0.0f,1.0f), "%ld error(s) occured.\n\n", messages.size());
ImGui::PushTextWrapPos(ImGui::GetCursorPos().x + width);
for (list<string>::iterator it=messages.begin(); it != messages.end(); ++it) {
ImGui::Text("%s\n", (*it).c_str());
ImGui::Separator();
}
ImGui::PopTextWrapPos();
ImGui::Dummy(ImVec2(width * 0.8f, 0)); ImGui::SameLine(); // right align
if (ImGui::Button("Ok", ImVec2(width * 0.2f, 0))) {
ImGui::CloseCurrentPopup();
// messages have been seen
messages.clear();
}
ImGui::SetItemDefaultFocus();
ImGui::EndPopup();
}
}
// template info panel
inline void InfosPane(std::string vFilter, bool *vCantContinue)
// if vCantContinue is false, the user cant validate the dialog
@@ -491,7 +416,8 @@ void MainWindow::ShowStats(bool* p_open)
ImGui::Text("Mouse (%.1f,%.1f)", io.MousePos.x, io.MousePos.y);
else
ImGui::Text("Mouse <invalid>");
ImGui::Text("Window (%.1f,%.1f)", io.DisplaySize.x, io.DisplaySize.y);
ImGui::Text("Rendering %.1f FPS", io.Framerate);
ImGui::PopFont();
@@ -540,7 +466,7 @@ static void ShowAboutOpengl(bool* p_open)
ImGui::Text("OpenGL is the premier environment for developing portable, \ninteractive 2D and 3D graphics applications.");
if ( ImGui::Button( ICON_FA_EXTERNAL_LINK_ALT " https://www.opengl.org") )
OpenWebpage("https://www.opengl.org");
ImGuiToolkit::OpenWebpage("https://www.opengl.org");
ImGui::SameLine();
// static std::string allextensions( glGetString(GL_EXTENSIONS) );
@@ -606,7 +532,7 @@ static void ShowAboutGStreamer(bool* p_open)
ImGui::Text("GStreamer is licensed under the LGPL License.");
if ( ImGui::Button( ICON_FA_EXTERNAL_LINK_ALT " https://gstreamer.freedesktop.org") )
OpenWebpage("https://gstreamer.freedesktop.org/");
ImGuiToolkit::OpenWebpage("https://gstreamer.freedesktop.org/");
ImGui::SameLine();
static bool show_config_info = false;
@@ -694,10 +620,10 @@ void MainWindow::Render()
}
if (ImGui::MenuItem( ICON_FA_FILE_UPLOAD " Open", "Ctrl+O")) {
UserInterface::OpenFileMedia();
UserInterface::manager().OpenFileMedia();
}
if (ImGui::MenuItem( ICON_FA_POWER_OFF " Quit", "Ctrl+Q")) {
Rendering::Close();
Rendering::manager().Close();
}
ImGui::EndMenu();
}
@@ -784,17 +710,17 @@ void MainWindow::Render()
screenshot_step = 2;
break;
case 2:
Rendering::RequestScreenshot();
Rendering::manager().RequestScreenshot();
screenshot_step = 3;
break;
case 3:
{
if ( Rendering::CurrentScreenshot()->IsFull() ){
if ( Rendering::manager().CurrentScreenshot()->IsFull() ){
std::time_t t = std::time(0); // get time now
std::tm* now = std::localtime(&t);
std::string filename = ImGuiToolkit::DateTime() + "_vmixcapture.png";
Rendering::CurrentScreenshot()->SaveFile( filename.c_str() );
Rendering::CurrentScreenshot()->Clear();
Rendering::manager().CurrentScreenshot()->SaveFile( filename.c_str() );
Rendering::manager().CurrentScreenshot()->Clear();
}
screenshot_step = 4;
}

View File

@@ -5,16 +5,6 @@
#include <list>
using namespace std;
class MessageBox
{
public:
list<string> messages;
MessageBox();
void Append(const string& text);
void Render(float width);
};
class MainWindow
{
bool show_overlay_stats;
@@ -41,39 +31,48 @@ public:
class UserInterface
{
// own implementation of ImGui
static unsigned int textureicons;
static MainWindow mainwindow;
static MessageBox warnings;
static std::string currentFileDialog;
static std::string currentTextEdit;
unsigned int textureicons;
MainWindow mainwindow;
std::string currentFileDialog;
std::string currentTextEdit;
static void handleKeyboard();
static void handleMouse();
void handleKeyboard();
void handleMouse();
// Private Constructor
UserInterface();
UserInterface(UserInterface const& copy); // Not Implemented
UserInterface& operator=(UserInterface const& copy); // Not Implemented
public:
static UserInterface& manager()
{
// The only instance
static UserInterface _instance;
return _instance;
}
// pre-loop initialization
static bool Init();
bool Init();
// loop update start new frame
static void NewFrame();
void NewFrame();
// loop update rendering
static void Render();
void Render();
// Post-loop termination
static void Terminate();
// Boxer integration in OS of Error messages
static void Error(const string& text, const string& title = std::string());
// ImGui modal dialog for Warning messages
static void Warning(const char* fmt, ...);
void Terminate();
// Open an Open File dialog for TEXT file
static void OpenFileText();
void OpenFileText();
// Open an Open File dialog for IMAGE file
static void OpenFileImage();
void OpenFileImage();
// Open an Open File dialog for MEDIA file
static void OpenFileMedia();
static void OpenTextEditor(std::string text);
void OpenFileMedia();
//
void OpenTextEditor(std::string text);
};
#endif /* #define __UI_MANAGER_H_ */

View File

@@ -16,9 +16,9 @@
// vmix
#include "defines.h"
#include "ShaderManager.h"
#include "SettingsManager.h"
#include "ResourceManager.h"
#include "Shader.h"
#include "Settings.h"
#include "Resource.h"
#include "RenderingManager.h"
#include "UserInterfaceManager.h"
@@ -106,12 +106,10 @@ void drawMediaBackgound()
if ( !testmedia2.isOpen() )
return;
// rendering TRIANGLE geometries
rendering_shader.use();
rendering_shader.setUniform("render_projection", Rendering::Projection());
rendering_shader.setUniform("render_projection", Rendering::manager().Projection());
testmedia2.Update();
testmedia2.Bind();
@@ -201,13 +199,28 @@ void drawMediaBackgound()
void drawMediaPlayer()
{
static GstClockTime begin = GST_CLOCK_TIME_NONE;
static GstClockTime end = GST_CLOCK_TIME_NONE;
if ( !testmedia.isOpen() )
return;
testmedia.Update();
if ( begin == GST_CLOCK_TIME_NONE) {
begin = testmedia.Duration() / 5;
end = testmedia.Duration() / 3;
// if ( testmedia.addPlaySegment(begin, end) )
// std::cerr << " - first segment " << std::endl;
// begin *= 2;
// end *= 2;
// if ( testmedia.addPlaySegment(begin, end) )
// std::cerr << " - second segment " << std::endl;
}
ImGui::Begin("Media Player");
float width = ImGui::GetContentRegionAvail().x;
float spacing = ImGui::GetStyle().ItemInnerSpacing.x;
@@ -275,12 +288,26 @@ void drawMediaPlayer()
guint64 current_t = testmedia.Position();
guint64 seek_t = current_t;
guint64 begin = testmedia.Duration() / 5;
guint64 end = 4 * testmedia.Duration() / 5;
bool slider_pressed = ImGuiToolkit::TimelineSlider( "timeline", &seek_t, begin, end,
bool slider_pressed = ImGuiToolkit::TimelineSlider( "simpletimeline", &seek_t,
testmedia.Duration(), testmedia.FrameDuration());
// std::list<std::pair<guint64, guint64> > segments = testmedia.getPlaySegments();
// bool slider_pressed = ImGuiToolkit::TimelineSliderEdit( "timeline", &seek_t, testmedia.Duration(),
// testmedia.FrameDuration(), segments);
// if (!segments.empty()) {
// // segments have been modified
// g_print("Segments modified \n");
// for (std::list< std::pair<guint64, guint64> >::iterator s = segments.begin(); s != segments.end(); s++){
// MediaSegment newsegment(s->first, s->second);
// testmedia.removeAllPlaySegmentOverlap(newsegment);
// if (!testmedia.addPlaySegment(newsegment))
// g_print("new Segment could not be added \n");
// }
// }
// 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) > testmedia.FrameDuration() ) {
@@ -300,7 +327,6 @@ void drawMediaPlayer()
testmedia.Play( media_play );
}
// display info
ImGui::Text("Dimension %d x %d", testmedia.Width(), testmedia.Height());
ImGui::Text("Framerate %.2f / %.2f", testmedia.UpdateFrameRate() , testmedia.FrameRate() );
@@ -320,46 +346,48 @@ int main(int, char**)
///
/// RENDERING INIT
///
if ( !Rendering::Init() )
if ( !Rendering::manager().Init() )
return 1;
///
/// UI INIT
///
if ( !UserInterface::Init() )
if ( !UserInterface::manager().Init() )
return 1;
///
/// GStreamer
///
#ifndef NDEBUG
gst_debug_set_active(TRUE);
gst_debug_set_default_threshold (GST_LEVEL_WARNING);
gst_debug_set_active(TRUE);
#endif
// 1
// testmedia.Open("file:///home/bhbn/Images/2014-10-18_16-46-47.jpg");
// testmedia.Open("file:///home/bhbn/Videos/balls.gif");
// testmedia.Open("file:///home/bhbn/Videos/SIGGRAPH92_1.avi");
// testmedia.Open("file:///home/bhbn/Videos/fish.mp4");
// testmedia.Open("file:///home/bhbn/Videos/iss.mov");
testmedia.Open("file:///home/bhbn/Videos/TearsOfSteel_720p_h265.mkv");
testmedia.Open("file:///home/bhbn/Videos/fish.mp4");
// testmedia.Open("file:///home/bhbn/Videos/jean/Solitude1080p.mov");
// testmedia.Open("file:///home/bhbn/Videos/TearsOfSteel_720p_h265.mkv");
// testmedia.Open("file:///home/bhbn/Videos/TestFormats/_h264GoldenLamps.mkv");
// testmedia.Open("file:///home/bhbn/Videos/TestEncoding/vpxvp9high.webm");
// testmedia.Open("file:///home/bhbn/Videos/iss.mov");
testmedia.Play(false);
// Add draw callbacks to the Rendering
Rendering::AddDrawCallback(drawMediaPlayer);
Rendering::manager().AddDrawCallback(drawMediaPlayer);
// 2
testmedia2.Open("file:///home/bhbn/Videos/iss.mov");
// testmedia2.Open("file:///home/bhbn/Images/svg/drawing.svg");
// testmedia2.Open("file:///home/bhbn/Images/svg/drawing.svg");
// testmedia2.Open("file:///home/bhbn/Videos/Upgrade.2018.720p.AMZN.WEB-DL.DDP5.1.H.264-NTG.m4v");
testmedia2.Play(true);
// create our geometries
create_square(vbo, vao, ebo);
// Add draw callbacks to the Rendering
Rendering::AddDrawCallback(drawMediaBackgound);
Rendering::manager().AddDrawCallback(drawMediaBackgound);
// // load an image
// textureimagepng = loadPNG("/home/bhbn/Videos/iss_snap.png", &texturear);
@@ -367,20 +395,21 @@ int main(int, char**)
// init shader
rendering_shader.load("shaders/texture-shader.vs", "shaders/texture-shader.fs");
UserInterface::OpenTextEditor( Resource::getText("shaders/texture-shader.vs") );
UserInterface::manager().OpenTextEditor( Resource::getText("shaders/texture-shader.vs") );
// Main loop
while ( Rendering::isActive() )
///
/// Main LOOP
///
while ( Rendering::manager().isActive() )
{
Rendering::Draw();
Rendering::manager().Draw();
}
testmedia.Close();
testmedia2.Close();
UserInterface::Terminate();
Rendering::Terminate();
UserInterface::manager().Terminate();
Rendering::manager().Terminate();
Settings::Save();

Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.6 KiB

View File

@@ -15,13 +15,13 @@
height="64"
id="svg3744"
sodipodi:version="0.32"
inkscape:version="0.91 r13725"
inkscape:version="0.92.4 (5da689c313, 2019-01-14)"
version="1.0"
sodipodi:docname="glmixer.svg"
sodipodi:docname="v-mix.svg"
inkscape:output_extension="org.inkscape.output.svg.inkscape"
inkscape:export-filename="/home/bh/Developments/GraphicLiveMixer/icons/glmixer.png"
inkscape:export-xdpi="45"
inkscape:export-ydpi="45">
inkscape:export-filename="/home/bhbn/Developments/v-mix/rsc/images/v-mix_256x256.png"
inkscape:export-xdpi="405.16815"
inkscape:export-ydpi="405.16815">
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
@@ -29,9 +29,9 @@
borderopacity="1.0"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:zoom="5.8802804"
inkscape:cx="-5.1163318"
inkscape:cy="38.373326"
inkscape:zoom="16.631945"
inkscape:cx="40.007713"
inkscape:cy="45.667662"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:document-units="px"
@@ -41,11 +41,11 @@
showborder="true"
objecttolerance="1"
guidetolerance="10000"
inkscape:window-width="2048"
inkscape:window-height="1126"
inkscape:window-x="0"
inkscape:window-y="26"
inkscape:window-maximized="1"
inkscape:window-width="2283"
inkscape:window-height="1885"
inkscape:window-x="1302"
inkscape:window-y="105"
inkscape:window-maximized="0"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
@@ -80,7 +80,6 @@
width="260" />
</pattern>
<linearGradient
inkscape:collect="always"
id="linearGradient5756"
osb:paint="gradient">
<stop
@@ -125,18 +124,6 @@
height="260"
width="260" />
</pattern>
<linearGradient
inkscape:collect="always"
id="linearGradient4165">
<stop
style="stop-color:#000000;stop-opacity:1;"
offset="0"
id="stop4167" />
<stop
style="stop-color:#000000;stop-opacity:0;"
offset="1"
id="stop4169" />
</linearGradient>
<inkscape:perspective
sodipodi:type="inkscape:persp3d"
inkscape:vp_x="0 : 8 : 1"
@@ -175,27 +162,8 @@
fx="8"
fy="8"
r="6.75"
gradientUnits="userSpaceOnUse" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4165"
id="linearGradient4171"
x1="-4.0976267"
y1="-1.8129851"
x2="8.3987904"
y2="7.1147871"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.73981462,0,0,1.055413,1.3566253,0.16867927)" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4165"
id="linearGradient5990"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.72647568,0,0,1.0777103,6.2654335,4.8979284)"
x1="16.436571"
y1="12.486804"
x2="4.1052761"
y2="3.7362654" />
gradientTransform="matrix(3.7398771,0.00904054,-0.00860863,3.5612078,2.9498521,-45.361987)" />
</defs>
<metadata
id="metadata3749">
@@ -205,7 +173,7 @@
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
@@ -214,40 +182,21 @@
inkscape:label="Layer 1"
inkscape:groupmode="layer"
transform="translate(-0.8,48.8)">
<g
id="g6034"
transform="matrix(4.2122429,0,0,4.2122429,-0.8979432,-50.497943)">
<path
inkscape:connector-curvature="0"
style="display:inline;overflow:visible;visibility:visible;opacity:0.2;fill:#848484;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:3.5999999;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;enable-background:accumulate"
d="M 8,0.8 C 4.0256,0.8 0.8,4.0256 0.8,8 c 0,3.9744 3.2256,7.2 7.2,7.2 3.9744,0 7.2,-3.2256 7.2,-7.2 C 15.2,4.0256 11.9744,0.8 8,0.8 Z m 0,0.9 c 3.4776,0 6.3,2.8224 6.3,6.3 0,3.4776 -2.8224,6.3 -6.3,6.3 C 4.5224,14.3 1.7,11.4776 1.7,8 1.7,4.5224 4.5224,1.7 8,1.7 Z"
id="path4090" />
<circle
r="6.3000002"
cy="8"
cx="8"
style="display:inline;overflow:visible;visibility:visible;opacity:0.5;fill:url(#radialGradient4161);fill-opacity:1;fill-rule:nonzero;stroke:#b536b5;stroke-width:0.40000001;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;enable-background:accumulate"
id="path4096" />
<g
transform="matrix(0,-1,1,0,0.00722897,15.959713)"
id="g6011">
<rect
style="fill:url(#linearGradient4171);fill-opacity:1;stroke:#f0ff2a;stroke-width:0.17672691;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect4163"
width="6.7404575"
height="6.4997482"
x="2.2274544"
y="2.2708783"
ry="0.64272904" />
<rect
ry="0.65630776"
y="7.0445399"
x="7.1205611"
height="6.6370654"
width="6.618926"
id="rect5988"
style="fill:url(#linearGradient5990);fill-opacity:1;stroke:#f0ff2a;stroke-width:0.17696671;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
</g>
</g>
<path
id="path4090"
d="m 32.8,-47.128149 c -16.741138,0 -30.3281489,13.587011 -30.3281489,30.328149 0,16.74113838 13.5870109,30.328149 30.3281489,30.328149 16.741138,0 30.328149,-13.58701062 30.328149,-30.328149 0,-16.741138 -13.587011,-30.328149 -30.328149,-30.328149 z m 0,3.791019 c 14.648496,0 26.53713,11.888634 26.53713,26.53713 C 59.33713,-2.1515039 47.448496,9.7371305 32.8,9.7371305 18.151504,9.7371305 6.2628697,-2.1515039 6.2628697,-16.8 6.2628697,-31.448496 18.151504,-43.33713 32.8,-43.33713 Z"
style="display:inline;overflow:visible;visibility:visible;opacity:0.2;fill:#848484;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:4.21224308;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:3.5999999;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
id="path4096"
style="display:inline;overflow:visible;visibility:visible;opacity:0.80100002;fill:url(#radialGradient4161);fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:4.54984188;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:0.64077669;marker:none;marker-start:none;marker-mid:none;marker-end:none;enable-background:accumulate"
sodipodi:type="arc"
sodipodi:cx="32.799999"
sodipodi:cy="-16.799999"
sodipodi:rx="24.147949"
sodipodi:ry="24.147949"
sodipodi:start="4.7127834"
sodipodi:end="4.7119507"
d="M 32.809524,-40.947947 A 24.147949,24.147949 0 0 1 56.947948,-16.795502 24.147949,24.147949 0 0 1 32.800529,7.34795 24.147949,24.147949 0 0 1 8.6520507,-16.794443 24.147949,24.147949 0 0 1 32.789416,-40.947946 l 0.01058,24.147947 z" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 322 KiB

After

Width:  |  Height:  |  Size: 321 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB