mirror of
https://github.com/brunoherbelin/vimix.git
synced 2025-12-11 18:34:58 +01:00
Complete refactoring
This commit is contained in:
@@ -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
|
||||
)
|
||||
|
||||
370
ImGuiToolkit.cpp
370
ImGuiToolkit.cpp
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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
77
Log.cpp
@@ -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
11
Log.h
@@ -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_
|
||||
|
||||
104
MediaPlayer.cpp
104
MediaPlayer.cpp
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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[]);
|
||||
|
||||
@@ -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
30
Resource.h
Normal 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_ */
|
||||
@@ -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 */
|
||||
@@ -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
47
Settings.h
Normal 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_ */
|
||||
@@ -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 */
|
||||
@@ -1,5 +1,5 @@
|
||||
#include "ShaderManager.h"
|
||||
#include "ResourceManager.h"
|
||||
#include "Shader.h"
|
||||
#include "Resource.h"
|
||||
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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_ */
|
||||
|
||||
83
main.cpp
83
main.cpp
@@ -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 |
@@ -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 |
BIN
rsc/images/v-mix_256x256.png
Normal file
BIN
rsc/images/v-mix_256x256.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 26 KiB |
Reference in New Issue
Block a user