init
This commit is contained in:
+553
@@ -0,0 +1,553 @@
|
||||
/*********************************************************************
|
||||
* Software License Agreement (AGPL-3 License)
|
||||
*
|
||||
* OpenViBE Designer
|
||||
* Based on OpenViBE V1.1.0, Copyright (C) Inria, 2006-2015
|
||||
* Copyright (C) Inria, 2015-2017,V1.0
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "mCBoxAlgorithmViz.hpp"
|
||||
|
||||
// OpenGL 1.2
|
||||
#ifndef GL_BGRA
|
||||
# define GL_BGRA 0x80E1
|
||||
#endif // GL_BGRA
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace AdvancedVisualization {
|
||||
|
||||
template <int i>
|
||||
class toolbar_sort_changed_
|
||||
{
|
||||
public:
|
||||
static void callback(GtkButton* /*button*/, CBoxAlgorithmViz* box)
|
||||
{
|
||||
box->m_RendererCtx->sortSelectedChannel(i);
|
||||
box->m_RedrawNeeded = true;
|
||||
}
|
||||
};
|
||||
|
||||
static void ChannelSelectionChanged(GtkTreeSelection* selection, CRendererContext* ctx)
|
||||
{
|
||||
size_t i = 0;
|
||||
GtkTreeView* treeView = gtk_tree_selection_get_tree_view(selection);
|
||||
GtkTreeModel* treeModel = gtk_tree_view_get_model(treeView);
|
||||
if (treeModel != nullptr)
|
||||
{
|
||||
GtkTreeIter iter;
|
||||
if (gtk_tree_model_get_iter_first(treeModel, &iter) != 0)
|
||||
{
|
||||
do
|
||||
{
|
||||
if (gtk_tree_selection_iter_is_selected(selection, &iter) != 0) { ctx->selectChannel(i); }
|
||||
else { ctx->unselectChannel(i); }
|
||||
i++;
|
||||
} while (gtk_tree_model_iter_next(treeModel, &iter) != 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void SpinbuttonTimeScaleChangeValueCB(GtkSpinButton* button, CRendererContext* ctx)
|
||||
{
|
||||
ctx->setTimeScale(size_t(gtk_spin_button_get_value(button) * (1LL << 32)));
|
||||
}
|
||||
|
||||
static void SpinbuttonElementCountChangeValueCB(GtkSpinButton* button, CRendererContext* ctx)
|
||||
{
|
||||
ctx->setElementCount(size_t(gtk_spin_button_get_value(button)));
|
||||
}
|
||||
|
||||
static void CheckbuttonPositiveToggledCB(GtkToggleButton* button, CRendererContext* ctx) { ctx->setPositiveOnly(gtk_toggle_button_get_active(button) != 0); }
|
||||
|
||||
static void CheckbuttonShowScaleToggledCB(GtkToggleButton* button, CRendererContext* ctx)
|
||||
{
|
||||
ctx->setScaleVisibility(gtk_toggle_button_get_active(button) != 0);
|
||||
}
|
||||
|
||||
static void ButtonVideoRecordingPressedCB(GtkButton* button, CBoxAlgorithmViz* box)
|
||||
{
|
||||
box->m_IsVideoOutputWorking = !box->m_IsVideoOutputWorking;
|
||||
gtk_button_set_label(button, box->m_IsVideoOutputWorking ? GTK_STOCK_MEDIA_PAUSE : GTK_STOCK_MEDIA_RECORD);
|
||||
}
|
||||
|
||||
static void RangeERPValueChangedCB(GtkRange* range, GtkLabel* label)
|
||||
{
|
||||
char str[1024];
|
||||
sprintf(str, "%.02f%%", gtk_range_get_value(range) * 100);
|
||||
gtk_label_set_text(label, str);
|
||||
getContext().stepERPFractionBy(float(gtk_range_get_value(range)) - getContext().getERPFraction());
|
||||
}
|
||||
|
||||
static void ButtonERPPlayPausePressedCB(GtkButton* /*button*/, CRendererContext* ctx) { ctx->setERPPlayerActive(!ctx->isERPPlayerActive()); }
|
||||
|
||||
static void SpinbuttonFreqBandMinChangeValueCB(GtkSpinButton* button, CRendererContext* ctx)
|
||||
{
|
||||
ctx->setMinimumSpectrumFrequency(size_t(gtk_spin_button_get_value(button)));
|
||||
}
|
||||
|
||||
static void SpinbuttonFreqBandMaxChangeValueCB(GtkSpinButton* button, CRendererContext* ctx)
|
||||
{
|
||||
ctx->setMaximumSpectrumFrequency(size_t(gtk_spin_button_get_value(button)));
|
||||
}
|
||||
//---------------------------------------------------------------------------------------------------
|
||||
|
||||
//---------------------------------------------------------------------------------------------------
|
||||
bool CBoxAlgorithmViz::initialize()
|
||||
|
||||
{
|
||||
m_RendererCtx = new CRendererContext();
|
||||
m_SubRendererCtx = new CRendererContext();
|
||||
|
||||
// Sets default setting values
|
||||
m_Colors.clear();
|
||||
m_Localisation = CString("");
|
||||
m_TemporalCoherence = ETemporalCoherence::TimeLocked;
|
||||
m_NElement = 50;
|
||||
m_TimeScale = 10LL << 32;
|
||||
m_IsPositive = false;
|
||||
m_IsTimeLocked = true;
|
||||
m_IsScaleVisible = true;
|
||||
m_TextureID = 0;
|
||||
m_lastProcessTime = 0;
|
||||
m_Time1 = 0;
|
||||
m_Time2 = 0;
|
||||
CString color = CString("100,100,100");
|
||||
m_ColorGradient = CString("0:0,0,0; 100:100,100,100");
|
||||
m_XYZPlotHasDepth = false;
|
||||
m_DataScale = 1;
|
||||
m_Translucency = 1;
|
||||
|
||||
|
||||
// Initializes fast forward behavior
|
||||
m_fastForwardMaxFactorHD = float(this->getConfigurationManager().expandAsFloat("${AdvancedViz_HighDefinition_FastForwardFactor}", 5.F));
|
||||
m_fastForwardMaxFactorLD = float(this->getConfigurationManager().expandAsFloat("${AdvancedViz_LowDefinition_FastForwardFactor}", 20.F));
|
||||
|
||||
// Gets data stream type
|
||||
this->getStaticBoxContext().getInputType(0, m_TypeID);
|
||||
|
||||
// Prepares GUI
|
||||
m_Builder = gtk_builder_new();
|
||||
gtk_builder_add_from_file(m_Builder, std::string(Directories::getDataDir() + "/plugins/advanced-visualization.ui").c_str(), nullptr);
|
||||
|
||||
GtkWidget* main = GTK_WIDGET(gtk_builder_get_object(m_Builder, "table"));
|
||||
GtkWidget* toolbar = GTK_WIDGET(gtk_builder_get_object(m_Builder, "toolbar-window"));
|
||||
m_Viewport = GTK_WIDGET(gtk_builder_get_object(m_Builder, "viewport"));
|
||||
m_Top = GTK_WIDGET(gtk_builder_get_object(m_Builder, "label_top"));
|
||||
m_Left = GTK_WIDGET(gtk_builder_get_object(m_Builder, "drawingarea_left"));
|
||||
m_Right = GTK_WIDGET(gtk_builder_get_object(m_Builder, "drawingarea_right"));
|
||||
m_Bottom = GTK_WIDGET(gtk_builder_get_object(m_Builder, "drawingarea_bottom"));
|
||||
m_CornerLeft = GTK_WIDGET(gtk_builder_get_object(m_Builder, "label_corner_left"));
|
||||
m_CornerRight = GTK_WIDGET(gtk_builder_get_object(m_Builder, "label_corner_right"));
|
||||
|
||||
// Gets important widgets
|
||||
m_TimeScaleW = GTK_WIDGET(gtk_builder_get_object(m_Builder, "spinbutton_time_scale"));
|
||||
m_nElementW = GTK_WIDGET(gtk_builder_get_object(m_Builder, "spinbutton_element_count"));
|
||||
m_ERPRange = GTK_WIDGET(gtk_builder_get_object(m_Builder, "range_erp"));
|
||||
m_ERPPlayerButton = GTK_WIDGET(gtk_builder_get_object(m_Builder, "button_erp_play_pause"));
|
||||
m_ERPPlayer = GTK_WIDGET(gtk_builder_get_object(m_Builder, "table_erp"));
|
||||
m_ScaleVisible = GTK_WIDGET(gtk_builder_get_object(m_Builder, "checkbutton_show_scale"));
|
||||
m_FrequencyBandMin = GTK_WIDGET(gtk_builder_get_object(m_Builder, "spinbutton_freq_band_min"));
|
||||
m_FrequencyBandMax = GTK_WIDGET(gtk_builder_get_object(m_Builder, "spinbutton_freq_band_max"));
|
||||
|
||||
m_ChannelTreeView = GTK_TREE_VIEW(gtk_builder_get_object(m_Builder, "expander_select_treeview"));
|
||||
m_ChannelListStore = GTK_LIST_STORE(gtk_builder_get_object(m_Builder, "liststore_select"));
|
||||
|
||||
gtk_tree_selection_set_mode(gtk_tree_view_get_selection(m_ChannelTreeView), GTK_SELECTION_MULTIPLE);
|
||||
|
||||
// Sets default spectrum frequency range
|
||||
gtk_spin_button_set_value(GTK_SPIN_BUTTON(m_FrequencyBandMin), 2);
|
||||
gtk_spin_button_set_value(GTK_SPIN_BUTTON(m_FrequencyBandMax), 48);
|
||||
|
||||
// Connects GTK signals
|
||||
g_signal_connect(gtk_builder_get_object(m_Builder, "expander_sort_button_default"), "pressed", G_CALLBACK(toolbar_sort_changed_<1>::callback), this);
|
||||
g_signal_connect(gtk_builder_get_object(m_Builder, "expander_sort_button_alpha"), "pressed", G_CALLBACK(toolbar_sort_changed_<2>::callback), this);
|
||||
g_signal_connect(gtk_builder_get_object(m_Builder, "expander_sort_button_reversed"), "pressed", G_CALLBACK(toolbar_sort_changed_<3>::callback), this);
|
||||
g_signal_connect(gtk_builder_get_object(m_Builder, "expander_sort_button_left_right"), "pressed", G_CALLBACK(toolbar_sort_changed_<4>::callback), this);
|
||||
g_signal_connect(gtk_builder_get_object(m_Builder, "expander_sort_button_front_back"), "pressed", G_CALLBACK(toolbar_sort_changed_<5>::callback), this);
|
||||
g_signal_connect(gtk_builder_get_object(m_Builder, "spinbutton_time_scale"), "value-changed", G_CALLBACK(SpinbuttonTimeScaleChangeValueCB), m_RendererCtx);
|
||||
g_signal_connect(gtk_builder_get_object(m_Builder, "spinbutton_element_count"), "value-changed", G_CALLBACK(SpinbuttonElementCountChangeValueCB),
|
||||
m_RendererCtx);
|
||||
g_signal_connect(gtk_builder_get_object(m_Builder, "spinbutton_element_count"), "value-changed", G_CALLBACK(SpinbuttonElementCountChangeValueCB),
|
||||
m_SubRendererCtx);
|
||||
g_signal_connect(gtk_builder_get_object(m_Builder, "checkbutton_positive"), "toggled", G_CALLBACK(CheckbuttonPositiveToggledCB), m_RendererCtx);
|
||||
g_signal_connect(gtk_builder_get_object(m_Builder, "checkbutton_show_scale"), "toggled", G_CALLBACK(CheckbuttonShowScaleToggledCB),
|
||||
&OpenViBE::AdvancedVisualization::getContext());
|
||||
g_signal_connect(gtk_builder_get_object(m_Builder, "button_erp_play_pause"), "pressed", G_CALLBACK(ButtonERPPlayPausePressedCB),
|
||||
&OpenViBE::AdvancedVisualization::getContext());
|
||||
g_signal_connect(gtk_builder_get_object(m_Builder, "button_video_recording"), "pressed", G_CALLBACK(ButtonVideoRecordingPressedCB), this);
|
||||
g_signal_connect(gtk_builder_get_object(m_Builder, "range_erp"), "value-changed", G_CALLBACK(RangeERPValueChangedCB),
|
||||
gtk_builder_get_object(m_Builder, "label_erp_progress"));
|
||||
g_signal_connect(gtk_builder_get_object(m_Builder, "spinbutton_freq_band_min"), "value-changed", G_CALLBACK(SpinbuttonFreqBandMinChangeValueCB),
|
||||
m_RendererCtx);
|
||||
g_signal_connect(gtk_builder_get_object(m_Builder, "spinbutton_freq_band_max"), "value-changed", G_CALLBACK(SpinbuttonFreqBandMaxChangeValueCB),
|
||||
m_RendererCtx);
|
||||
|
||||
g_signal_connect(gtk_tree_view_get_selection(m_ChannelTreeView), "changed", G_CALLBACK(ChannelSelectionChanged), m_RendererCtx);
|
||||
|
||||
// Hides unnecessary widgets
|
||||
if (std::find(m_Parameters.begin(), m_Parameters.end(), S_DataScale) == m_Parameters.end())
|
||||
{
|
||||
gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(m_Builder, "checkbutton_positive")));
|
||||
}
|
||||
if (std::find(m_Parameters.begin(), m_Parameters.end(), S_ChannelLocalisation) == m_Parameters.end())
|
||||
{
|
||||
gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(m_Builder, "expander_sort")));
|
||||
}
|
||||
if (m_TypeID != OV_TypeId_Spectrum) { gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(m_Builder, "expander_freq_band"))); }
|
||||
gtk_widget_hide(m_ERPPlayer);
|
||||
|
||||
// Prepares 3D View
|
||||
m_GtkGLWidget.initialize(*this, m_Viewport, m_Left, m_Right, m_Bottom);
|
||||
m_GtkGLWidget.setPointSmoothingActive(this->getConfigurationManager().expandAsBoolean("${AdvancedViz_SmoothPoint}", false));
|
||||
|
||||
// Fowards widgets to the OpenViBE viz context
|
||||
if (!this->canCreatePluginObject(OVP_ClassId_Plugin_VisualizationCtx))
|
||||
{
|
||||
this->getLogManager() << Kernel::LogLevel_Error << "Visualization framework is not loaded" << "\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
m_visualizationCtx = dynamic_cast<VisualizationToolkit::IVisualizationContext*>(this->createPluginObject(OVP_ClassId_Plugin_VisualizationCtx));
|
||||
m_visualizationCtx->setWidget(*this, main);
|
||||
m_visualizationCtx->setToolbar(*this, toolbar);
|
||||
|
||||
// Parses box settings
|
||||
size_t settingIndex = 0;
|
||||
for (int iParameter : m_Parameters)
|
||||
{
|
||||
double value;
|
||||
switch (iParameter)
|
||||
{
|
||||
case S_ChannelLocalisation:
|
||||
m_Localisation = FSettingValueAutoCast(*this->getBoxAlgorithmContext(), settingIndex);
|
||||
break;
|
||||
case S_Caption:
|
||||
m_Caption = FSettingValueAutoCast(*this->getBoxAlgorithmContext(), settingIndex);
|
||||
break;
|
||||
case S_Color:
|
||||
color = FSettingValueAutoCast(*this->getBoxAlgorithmContext(), settingIndex);
|
||||
break;
|
||||
case S_ColorGradient:
|
||||
m_ColorGradient = FSettingValueAutoCast(*this->getBoxAlgorithmContext(), settingIndex);
|
||||
break;
|
||||
case S_DataPositive:
|
||||
m_IsPositive = FSettingValueAutoCast(*this->getBoxAlgorithmContext(), settingIndex);
|
||||
break;
|
||||
case S_TemporalCoherence:
|
||||
m_TemporalCoherence = ETemporalCoherence(size_t(FSettingValueAutoCast(*this->getBoxAlgorithmContext(), settingIndex)));
|
||||
break;
|
||||
case S_TimeScale:
|
||||
value = FSettingValueAutoCast(*this->getBoxAlgorithmContext(), settingIndex);
|
||||
m_TimeScale = size_t(value * (1LL << 32));
|
||||
break;
|
||||
case S_ElementCount:
|
||||
m_NElement = size_t(FSettingValueAutoCast(*this->getBoxAlgorithmContext(), settingIndex));
|
||||
break;
|
||||
case S_DataScale:
|
||||
m_DataScale = FSettingValueAutoCast(*this->getBoxAlgorithmContext(), settingIndex);
|
||||
break;
|
||||
case S_FlowerRingCount:
|
||||
m_NFlowerRing = size_t(FSettingValueAutoCast(*this->getBoxAlgorithmContext(), settingIndex));
|
||||
break;
|
||||
case S_Translucency:
|
||||
m_Translucency = FSettingValueAutoCast(*this->getBoxAlgorithmContext(), settingIndex);
|
||||
break;
|
||||
case S_ShowAxis:
|
||||
m_ShowAxis = FSettingValueAutoCast(*this->getBoxAlgorithmContext(), settingIndex);
|
||||
break;
|
||||
case S_XYZPlotHasDepth:
|
||||
m_XYZPlotHasDepth = FSettingValueAutoCast(*this->getBoxAlgorithmContext(), settingIndex);
|
||||
break;
|
||||
|
||||
case F_FixedChannelOrder:
|
||||
settingIndex--;
|
||||
gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(m_Builder, "expander_sort")));
|
||||
break;
|
||||
case F_FixedChannelSelection:
|
||||
settingIndex--;
|
||||
gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(m_Builder, "expander_select")));
|
||||
break;
|
||||
default:
|
||||
settingIndex--;
|
||||
break;
|
||||
}
|
||||
|
||||
settingIndex++;
|
||||
}
|
||||
|
||||
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(m_Builder, "checkbutton_positive")), gboolean(m_IsPositive));
|
||||
|
||||
// Parses color string
|
||||
parseColor(m_Color, color.toASCIIString());
|
||||
m_Colors.push_back(m_Color);
|
||||
|
||||
// Parses color string - special for instant oscilloscope which can have several inputs
|
||||
for (size_t i = settingIndex; i < this->getStaticBoxContext().getSettingCount(); ++i)
|
||||
{
|
||||
color = FSettingValueAutoCast(*this->getBoxAlgorithmContext(), i);
|
||||
parseColor(m_Color, color.toASCIIString());
|
||||
m_Colors.push_back(m_Color);
|
||||
}
|
||||
|
||||
// Sets caption
|
||||
if (m_Caption != CString("")) { gtk_label_set_text(GTK_LABEL(m_Top), std::string(m_Caption.toASCIIString()).c_str()); }
|
||||
|
||||
// Sets time scale
|
||||
if (m_TemporalCoherence == ETemporalCoherence::TimeLocked)
|
||||
{
|
||||
gtk_spin_button_set_value(GTK_SPIN_BUTTON(gtk_builder_get_object(m_Builder, "spinbutton_time_scale")), (m_TimeScale >> 22) / 1024.);
|
||||
m_IsTimeLocked = true;
|
||||
}
|
||||
else { gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(m_Builder, "vbox_time_scale"))); }
|
||||
|
||||
// Sets matrix count
|
||||
if (m_TemporalCoherence == ETemporalCoherence::Independant)
|
||||
{
|
||||
gtk_spin_button_set_value(GTK_SPIN_BUTTON(gtk_builder_get_object(m_Builder, "spinbutton_element_count")), double(m_NElement));
|
||||
m_IsTimeLocked = false;
|
||||
}
|
||||
else { gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(m_Builder, "vbox_element_count"))); }
|
||||
|
||||
// Shows / hides scale
|
||||
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(m_ScaleVisible), gboolean(m_RendererCtx->getScaleVisibility()));
|
||||
|
||||
// Reads channel localisation
|
||||
if (m_Localisation != CString(""))
|
||||
{
|
||||
Kernel::IAlgorithmProxy* channelPosReader = &this->getAlgorithmManager().getAlgorithm(
|
||||
this->getAlgorithmManager().createAlgorithm(OVP_GD_ClassId_Algorithm_OVMatrixFileReader));
|
||||
channelPosReader->initialize();
|
||||
|
||||
const Kernel::TParameterHandler<CString*> ip_filename(
|
||||
channelPosReader->getInputParameter(OVP_GD_Algorithm_OVMatrixFileReader_InputParameterId_Filename));
|
||||
Kernel::TParameterHandler<CMatrix*> op_matrix(channelPosReader->getOutputParameter(OVP_GD_Algorithm_OVMatrixFileReader_OutputParameterId_Matrix));
|
||||
|
||||
*ip_filename = m_Localisation;
|
||||
|
||||
channelPosReader->process();
|
||||
|
||||
if (op_matrix->getDimensionCount() != 2 || op_matrix->getDimensionSize(1) != 3)
|
||||
{
|
||||
this->getLogManager() << Kernel::LogLevel_Warning << "Invalid channel localisation file " << m_Localisation << "\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
const size_t nChannel = op_matrix->getDimensionSize(0);
|
||||
double* buffer = op_matrix->getBuffer();
|
||||
for (size_t i = 0; i < nChannel; ++i)
|
||||
{
|
||||
std::string name = trim(op_matrix->getDimensionLabel(0, i));
|
||||
std::transform(name.begin(), name.end(), name.begin(), tolower);
|
||||
m_ChannelPositions[name] = CVertex(-buffer[1], buffer[2], -buffer[0]);
|
||||
buffer += 3;
|
||||
}
|
||||
}
|
||||
|
||||
channelPosReader->uninitialize();
|
||||
this->getAlgorithmManager().releaseAlgorithm(*channelPosReader);
|
||||
channelPosReader = nullptr;
|
||||
}
|
||||
|
||||
// Gets frame base path for video output, if the variable is not defined, no video output is performed
|
||||
const CString basePath = this->getConfigurationManager().expand("${AdvancedVisualization_VideoOutputPath}");
|
||||
const CString sessionId = this->getConfigurationManager().expand("[$core{date}-$core{time}]");
|
||||
const CString widgetName = this->getStaticBoxContext().getName();
|
||||
m_FrameFilenameFormat = basePath + sessionId + widgetName + CString("-%06i.png");
|
||||
m_IsVideoOutputEnabled = (basePath != CString(""));
|
||||
m_IsVideoOutputWorking = false;
|
||||
m_FrameId = 0;
|
||||
gtk_widget_set_visible(GTK_WIDGET(gtk_builder_get_object(m_Builder, "hbox_video_recording")), m_IsVideoOutputEnabled ? TRUE : FALSE);
|
||||
gtk_label_set_markup(GTK_LABEL(gtk_builder_get_object(m_Builder, "label_video_recording_filename")),
|
||||
(CString("<span foreground=\"darkblue\"><small>") + m_FrameFilenameFormat + CString("</small></span>")).toASCIIString());
|
||||
|
||||
m_Width = 0;
|
||||
m_Height = 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CBoxAlgorithmViz::uninitialize()
|
||||
|
||||
{
|
||||
g_object_unref(m_Builder);
|
||||
m_Builder = nullptr;
|
||||
|
||||
getContext().stepERPFractionBy(-getContext().getERPFraction());
|
||||
getContext().setERPPlayerActive(false);
|
||||
|
||||
delete m_SubRendererCtx;
|
||||
m_SubRendererCtx = nullptr;
|
||||
|
||||
delete m_RendererCtx;
|
||||
m_RendererCtx = nullptr;
|
||||
|
||||
this->releasePluginObject(m_visualizationCtx);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CBoxAlgorithmViz::processClock(Kernel::CMessageClock& /*msg*/)
|
||||
{
|
||||
const uint64_t currentTime = this->getPlayerContext().getCurrentTime();
|
||||
|
||||
const uint64_t minDeltaTimeHD = (1LL << 32) / 16;
|
||||
const uint64_t minDeltaTimeLD = (1LL << 32);
|
||||
const uint64_t minDeltaTimeLD2 = (1LL << 32) * 5;
|
||||
|
||||
uint64_t minDeltaTime;
|
||||
if (this->getPlayerContext().getStatus() == Kernel::EPlayerStatus::Play) { minDeltaTime = minDeltaTimeHD; }
|
||||
else
|
||||
{
|
||||
const auto fastForwardMaxFactor = float(this->getPlayerContext().getCurrentFastForwardMaximumFactor());
|
||||
if (fastForwardMaxFactor <= m_fastForwardMaxFactorHD) { minDeltaTime = minDeltaTimeHD; }
|
||||
else if (fastForwardMaxFactor <= m_fastForwardMaxFactorLD)
|
||||
{
|
||||
const float alpha = (fastForwardMaxFactor - m_fastForwardMaxFactorHD) / (m_fastForwardMaxFactorLD - m_fastForwardMaxFactorHD);
|
||||
minDeltaTime = uint64_t((minDeltaTimeLD * alpha) + minDeltaTimeHD * (1.F - alpha));
|
||||
}
|
||||
else { minDeltaTime = minDeltaTimeLD2; }
|
||||
}
|
||||
|
||||
if (currentTime > m_lastProcessTime + minDeltaTime || this->getPlayerContext().getStatus() == Kernel::EPlayerStatus::Step
|
||||
|| this->getPlayerContext().getStatus() == Kernel::EPlayerStatus::Pause)
|
||||
{
|
||||
m_lastProcessTime = currentTime;
|
||||
this->m_RedrawNeeded = true;
|
||||
this->getBoxAlgorithmContext()->markAlgorithmAsReadyToProcess();
|
||||
}
|
||||
|
||||
this->updateRulerVisibility();
|
||||
return true;
|
||||
}
|
||||
|
||||
void CBoxAlgorithmViz::updateRulerVisibility()
|
||||
{
|
||||
if (m_IsScaleVisible != m_RendererCtx->getScaleVisibility())
|
||||
{
|
||||
m_IsScaleVisible = m_RendererCtx->getScaleVisibility();
|
||||
|
||||
if ((gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(m_ScaleVisible)) != 0) != m_IsScaleVisible)
|
||||
{
|
||||
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(m_ScaleVisible), gboolean(m_IsScaleVisible));
|
||||
}
|
||||
|
||||
void (*action)(GtkWidget*) = m_IsScaleVisible ? gtk_widget_show : gtk_widget_hide;
|
||||
(*action)(this->m_Top);
|
||||
(*action)(this->m_Left);
|
||||
(*action)(this->m_Right);
|
||||
(*action)(this->m_Bottom);
|
||||
(*action)(this->m_CornerLeft);
|
||||
(*action)(this->m_CornerRight);
|
||||
}
|
||||
}
|
||||
|
||||
void CBoxAlgorithmViz::reshape(const int width, const int height)
|
||||
{
|
||||
m_Width = size_t(width);
|
||||
m_Height = size_t(height);
|
||||
m_RendererCtx->setAspect(float(width) / float(height));
|
||||
}
|
||||
|
||||
void CBoxAlgorithmViz::preDraw()
|
||||
{
|
||||
this->updateRulerVisibility();
|
||||
|
||||
if (m_TextureID == 0U) { m_TextureID = m_GtkGLWidget.createTexture(m_ColorGradient.toASCIIString()); }
|
||||
glBindTexture(GL_TEXTURE_1D, m_TextureID);
|
||||
|
||||
m_RendererCtx->setAspect(m_Viewport->allocation.width * 1.F / m_Viewport->allocation.height);
|
||||
}
|
||||
|
||||
void CBoxAlgorithmViz::postDraw()
|
||||
|
||||
{
|
||||
glPushAttrib(GL_ALL_ATTRIB_BITS);
|
||||
if (m_Ruler != nullptr) { m_Ruler->doRender(); }
|
||||
glPopAttrib();
|
||||
|
||||
if (m_IsVideoOutputEnabled && m_IsVideoOutputWorking && m_Width > 0 && m_Height > 0)
|
||||
{
|
||||
// Builds up filename to save PNG to
|
||||
char filename[1024];
|
||||
sprintf(filename, m_FrameFilenameFormat.toASCIIString(), ++m_FrameId);
|
||||
|
||||
// Reads OpenGL buffer and stores it to a cairo surface
|
||||
cairo_surface_t* cairoSurface = cairo_image_surface_create(CAIRO_FORMAT_RGB24, int(m_Width), int(m_Height));
|
||||
glReadPixels(0, 0, GLsizei(m_Width), GLsizei(m_Height), GL_BGRA, GL_UNSIGNED_BYTE, cairo_image_surface_get_data(cairoSurface));
|
||||
|
||||
// OpenGL buffers are defined bottom to top while PNG are defined top to bottom, this flips the acquired image
|
||||
const size_t size = 4; // should be 3
|
||||
std::vector<unsigned char> swaps(m_Width * size);
|
||||
unsigned char* swap = &swaps[0];
|
||||
unsigned char* src1 = cairo_image_surface_get_data(cairoSurface);
|
||||
unsigned char* src2 = cairo_image_surface_get_data(cairoSurface) + m_Width * (m_Height - 1) * size;
|
||||
for (size_t i = 0; i < m_Height / 2; ++i)
|
||||
{
|
||||
memcpy(swap, src1, m_Width * size);
|
||||
memcpy(src1, src2, m_Width * size);
|
||||
memcpy(src2, swap, m_Width * size);
|
||||
src1 += m_Width * size;
|
||||
src2 -= m_Width * size;
|
||||
}
|
||||
|
||||
// Pixels are ready to save
|
||||
cairo_surface_write_to_png(cairoSurface, filename);
|
||||
cairo_surface_destroy(cairoSurface);
|
||||
}
|
||||
}
|
||||
|
||||
void CBoxAlgorithmViz::mouseButton(const int x, const int y, const int button, const int status)
|
||||
{
|
||||
// Mouse interacts with local renderer context
|
||||
// m_MouseHandler.mouseButton(*m_rendererCtx, x, y, button, status);
|
||||
// Mouse interacts with global renderer context
|
||||
m_MouseHandler.mouseButton(getContext(), x, y, button, status);
|
||||
this->redraw();
|
||||
}
|
||||
|
||||
void CBoxAlgorithmViz::mouseMotion(const int x, const int y)
|
||||
{
|
||||
// Mouse interacts with local renderer context
|
||||
// m_MouseHandler.mouseMotion(*m_rendererCtx, x, y);
|
||||
// Mouse interacts with global renderer context
|
||||
m_MouseHandler.mouseMotion(getContext(), x, y);
|
||||
if (m_MouseHandler.hasButtonPressed()) { this->redraw(); }
|
||||
}
|
||||
|
||||
void CBoxAlgorithmViz::keyboard(const int x, const int y, const size_t key, const bool status)
|
||||
{
|
||||
std::cout << "keyboard : x=" << x << " y=" << y << " key=" << key << " status=" << (status ? "pressed" : "released");
|
||||
}
|
||||
|
||||
void CBoxAlgorithmViz::parseColor(color_t& rColor, const std::string& sColor)
|
||||
{
|
||||
float r, g, b;
|
||||
if (sscanf(sColor.c_str(), "%f,%f,%f", &r, &g, &b) == 3)
|
||||
{
|
||||
rColor.r = r * .01F;
|
||||
rColor.g = g * .01F;
|
||||
rColor.b = b * .01F;
|
||||
}
|
||||
else
|
||||
{
|
||||
rColor.r = 1;
|
||||
rColor.g = 1;
|
||||
rColor.b = 1;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace AdvancedVisualization
|
||||
} // namespace OpenViBE
|
||||
+385
@@ -0,0 +1,385 @@
|
||||
/*********************************************************************
|
||||
* Software License Agreement (AGPL-3 License)
|
||||
*
|
||||
* OpenViBE Designer
|
||||
* Based on OpenViBE V1.1.0, Copyright (C) Inria, 2006-2015
|
||||
* Copyright (C) Inria, 2015-2017,V1.0
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "m_defines.hpp"
|
||||
|
||||
#include <openvibe/ov_all.h>
|
||||
#include <toolkit/ovtk_all.h>
|
||||
#include <visualization-toolkit/ovviz_all.h>
|
||||
|
||||
#include <mensia/advanced-visualization.hpp>
|
||||
|
||||
#include <system/ovCTime.h>
|
||||
|
||||
#include "mTGtkGLWidget.hpp"
|
||||
#include "mCMouse.hpp"
|
||||
|
||||
#include "mIRuler.hpp"
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <cstdarg>
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace AdvancedVisualization {
|
||||
enum EParameter
|
||||
{
|
||||
// Parameter
|
||||
P_None,
|
||||
|
||||
// Input
|
||||
I_Matrix, I_Signal, I_Spectrum, I_TimeFrequency, I_Covariance, I_Stimulations,
|
||||
|
||||
// Setting
|
||||
S_ChannelLocalisation, S_TemporalCoherence, S_TimeScale, S_ElementCount, S_DataScale, S_Caption, S_DataPositive,
|
||||
S_Translucency, S_FlowerRingCount, S_Color, S_ColorGradient, S_ShowAxis, S_XYZPlotHasDepth,
|
||||
|
||||
// Flag
|
||||
F_CanAddInput, F_FixedChannelOrder, F_FixedChannelSelection, F_Unstable
|
||||
};
|
||||
|
||||
class CParameterSet
|
||||
{
|
||||
public:
|
||||
|
||||
explicit CParameterSet(int p, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, p);
|
||||
while (p != P_None)
|
||||
{
|
||||
m_parameters.push_back(p);
|
||||
p = va_arg(args, int);
|
||||
}
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
explicit operator const std::vector<int>&() const { return m_parameters; }
|
||||
|
||||
protected:
|
||||
|
||||
std::vector<int> m_parameters;
|
||||
};
|
||||
|
||||
class CBoxAlgorithmViz : public Toolkit::TBoxAlgorithm<Plugins::IBoxAlgorithm>
|
||||
{
|
||||
public:
|
||||
|
||||
typedef struct
|
||||
{
|
||||
float r, g, b;
|
||||
} color_t;
|
||||
|
||||
CBoxAlgorithmViz(const CIdentifier& classID, const std::vector<int>& parameters)
|
||||
: m_ClassID(classID), m_Parameters(parameters), m_MouseHandler(*this)
|
||||
{
|
||||
m_Color.r = 1;
|
||||
m_Color.g = 1;
|
||||
m_Color.b = 1;
|
||||
}
|
||||
|
||||
void release() override { delete this; }
|
||||
|
||||
uint64_t getClockFrequency() override { return (32LL << 32); }
|
||||
bool initialize() override;
|
||||
bool uninitialize() override;
|
||||
bool processInput(const size_t /*index*/) override { return true; }
|
||||
bool processClock(Kernel::CMessageClock& msg) override;
|
||||
|
||||
virtual void redrawTopLevelWindow(const bool immediate = false) { m_GtkGLWidget.redrawTopLevelWindow(immediate); }
|
||||
|
||||
virtual void redraw(const bool immediate = false)
|
||||
{
|
||||
const uint64_t currentTime = System::Time::zgetTime();
|
||||
if (m_RedrawNeeded || currentTime - m_LastRenderTime > ((1LL << 32) / 16))
|
||||
{
|
||||
// immediate |= (currentTime - m_lastRenderTime > ((1LL<<32)/4));
|
||||
m_GtkGLWidget.redraw(immediate);
|
||||
m_GtkGLWidget.redrawLeft(immediate);
|
||||
m_GtkGLWidget.redrawRight(immediate);
|
||||
m_GtkGLWidget.redrawBottom(immediate);
|
||||
m_LastRenderTime = currentTime;
|
||||
m_RedrawNeeded = false;
|
||||
}
|
||||
}
|
||||
|
||||
virtual void updateRulerVisibility();
|
||||
virtual void reshape(int width, int height);
|
||||
virtual void preDraw();
|
||||
virtual void postDraw();
|
||||
virtual void draw() { }
|
||||
virtual void drawLeft() { if (m_Ruler != nullptr) { m_Ruler->doRenderLeft(m_Left); } }
|
||||
virtual void drawRight() { if (m_Ruler != nullptr) { m_Ruler->doRenderRight(m_Right); } }
|
||||
virtual void drawBottom() { if (m_Ruler != nullptr) { m_Ruler->doRenderBottom(m_Bottom); } }
|
||||
virtual void mouseButton(int x, int y, int button, int status);
|
||||
virtual void mouseMotion(int x, int y);
|
||||
virtual void keyboard(int x, int y, size_t key, bool status);
|
||||
|
||||
protected:
|
||||
|
||||
static void parseColor(color_t& rColor, const std::string& sColor);
|
||||
|
||||
public:
|
||||
|
||||
CIdentifier m_ClassID = CIdentifier::undefined();
|
||||
std::vector<int> m_Parameters;
|
||||
uint64_t m_lastProcessTime = 0;
|
||||
|
||||
TGtkGLWidget<CBoxAlgorithmViz> m_GtkGLWidget;
|
||||
std::map<std::string, CVertex> m_ChannelPositions;
|
||||
|
||||
CRendererContext* m_RendererCtx = nullptr;
|
||||
CRendererContext* m_SubRendererCtx = nullptr;
|
||||
IRuler* m_Ruler = nullptr;
|
||||
CMouse m_MouseHandler;
|
||||
|
||||
CString m_Localisation;
|
||||
ETemporalCoherence m_TemporalCoherence = ETemporalCoherence::TimeLocked;
|
||||
uint64_t m_TimeScale = 0;
|
||||
size_t m_NElement = 0;
|
||||
double m_DataScale = 0.0;
|
||||
CString m_Caption;
|
||||
uint32_t m_TextureID = 0;
|
||||
size_t m_NFlowerRing = 0;
|
||||
double m_Translucency = 0.0;
|
||||
CString m_ColorGradient;
|
||||
bool m_ShowAxis = false;
|
||||
bool m_XYZPlotHasDepth = false;
|
||||
bool m_IsPositive = false;
|
||||
bool m_IsTimeLocked = false;
|
||||
bool m_IsScaleVisible = false;
|
||||
std::vector<color_t> m_Colors;
|
||||
color_t m_Color;
|
||||
|
||||
CIdentifier m_TypeID = CIdentifier::undefined();
|
||||
uint64_t m_Time1 = 0;
|
||||
uint64_t m_Time2 = 0;
|
||||
|
||||
float m_fastForwardMaxFactorHD = 0.0;
|
||||
float m_fastForwardMaxFactorLD = 0.0;
|
||||
|
||||
std::vector<float> m_Swaps;
|
||||
|
||||
GtkBuilder* m_Builder = nullptr;
|
||||
|
||||
GtkWidget* m_Viewport = nullptr;
|
||||
GtkWidget* m_Top = nullptr;
|
||||
GtkWidget* m_Left = nullptr;
|
||||
GtkWidget* m_Right = nullptr;
|
||||
GtkWidget* m_Bottom = nullptr;
|
||||
GtkWidget* m_CornerLeft = nullptr;
|
||||
GtkWidget* m_CornerRight = nullptr;
|
||||
|
||||
GtkWidget* m_TimeScaleW = nullptr;
|
||||
GtkWidget* m_nElementW = nullptr;
|
||||
GtkWidget* m_ERPRange = nullptr;
|
||||
GtkWidget* m_ERPPlayerButton = nullptr;
|
||||
GtkWidget* m_ERPPlayer = nullptr;
|
||||
GtkWidget* m_ScaleVisible = nullptr;
|
||||
GtkWidget* m_FrequencyBandMin = nullptr;
|
||||
GtkWidget* m_FrequencyBandMax = nullptr;
|
||||
|
||||
GtkTreeView* m_ChannelTreeView = nullptr;
|
||||
GtkListStore* m_ChannelListStore = nullptr;
|
||||
|
||||
size_t m_Width = 0;
|
||||
size_t m_Height = 0;
|
||||
|
||||
bool m_RebuildNeeded = false;
|
||||
bool m_RefreshNeeded = false;
|
||||
bool m_RedrawNeeded = false;
|
||||
uint64_t m_LastRenderTime = 0;
|
||||
|
||||
bool m_IsVideoOutputEnabled = false; // for video output
|
||||
bool m_IsVideoOutputWorking = false;
|
||||
size_t m_FrameId = 0;
|
||||
CString m_FrameFilenameFormat;
|
||||
|
||||
private:
|
||||
VisualizationToolkit::IVisualizationContext* m_visualizationCtx = nullptr;
|
||||
};
|
||||
|
||||
class CBoxAlgorithmVizListener : public Toolkit::TBoxListener<Plugins::IBoxListener>
|
||||
{
|
||||
public:
|
||||
|
||||
explicit CBoxAlgorithmVizListener(const std::vector<int>& parameters) : m_Parameters(parameters) { }
|
||||
|
||||
size_t getBaseSettingCount()
|
||||
{
|
||||
size_t result = 0;
|
||||
for (const auto& p : m_Parameters)
|
||||
{
|
||||
// if(p == I_Matrix) { result++; }
|
||||
// if(p == I_Signal) { result++; }
|
||||
// if(p == I_Spectrum) { result++; }
|
||||
// if(p == I_Covariance) { result++; }
|
||||
// if(p == I_Stimulations) { result++; }
|
||||
if (p == S_ChannelLocalisation) { result++; }
|
||||
if (p == S_TemporalCoherence) { result++; }
|
||||
if (p == S_TimeScale) { result++; }
|
||||
if (p == S_ElementCount) { result++; }
|
||||
if (p == S_DataScale) { result++; }
|
||||
if (p == S_Caption) { result++; }
|
||||
if (p == S_DataPositive) { result++; }
|
||||
if (p == S_Translucency) { result++; }
|
||||
if (p == S_FlowerRingCount) { result++; }
|
||||
if (p == S_Color) { result++; }
|
||||
if (p == S_ColorGradient) { result++; }
|
||||
if (p == S_ShowAxis) { result++; }
|
||||
if (p == S_XYZPlotHasDepth) { result++; }
|
||||
// if(p == F_CanAddInput) { result++; }
|
||||
// if(p == F_FixedChannelOrder) { result++; }
|
||||
// if(p == F_FixedChannelSelection) { result++; }
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool onInitialized(Kernel::IBox& /*box*/) override
|
||||
{
|
||||
#ifdef TARGET_OS_Windows
|
||||
//box.addAttribute(OV_AttributeId_Box_DocumentationURLBase, OpenViBE::CString("${Path_Root}/doc/Mensia Advanced Visualization Toolkit/Mensia Advanced Visualization Toolkit.chm::"));
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
bool onDefaultInitialized(Kernel::IBox& box) override
|
||||
{
|
||||
const bool isSignal = (std::find(m_Parameters.begin(), m_Parameters.end(), I_Signal) != m_Parameters.end());
|
||||
const bool isSpectrum = (std::find(m_Parameters.begin(), m_Parameters.end(), I_Spectrum) != m_Parameters.end());
|
||||
const bool isCovariance = (std::find(m_Parameters.begin(), m_Parameters.end(), I_Covariance) != m_Parameters.end());
|
||||
CIdentifier typeID = CIdentifier::undefined();
|
||||
|
||||
for (size_t i = 0; i < box.getInputCount(); ++i)
|
||||
{
|
||||
box.getInputType(i, typeID);
|
||||
if (typeID == OV_TypeId_StreamedMatrix)
|
||||
{
|
||||
if (isSignal) { box.setInputType(i, OV_TypeId_Signal); }
|
||||
if (isSpectrum) { box.setInputType(i, OV_TypeId_Spectrum); }
|
||||
if (isCovariance) { box.setInputType(i, OV_TypeId_CovarianceMatrix); }
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
_IsDerivedFromClass_Final_(OpenViBE::Toolkit::TBoxListener<OpenViBE::Plugins::IBoxListener>, OpenViBE::CIdentifier::undefined())
|
||||
|
||||
std::vector<int> m_Parameters;
|
||||
};
|
||||
|
||||
class CBoxAlgorithmVizDesc : public Plugins::IBoxAlgorithmDesc
|
||||
{
|
||||
public:
|
||||
|
||||
CString m_Name;
|
||||
CString m_CategoryName;
|
||||
CString m_ShortDesc;
|
||||
CString m_DetailedDesc;
|
||||
CIdentifier m_DescClassID = CIdentifier::undefined();
|
||||
CIdentifier m_ClassID = CIdentifier::undefined();
|
||||
CString m_AddedSoftwareVersion;
|
||||
CString m_UpdatedSoftwareVersion;
|
||||
std::vector<int> m_Parameters;
|
||||
|
||||
CBoxAlgorithmVizDesc(const CString& name, const CIdentifier& descClassID, const CIdentifier& classID,
|
||||
const CString& addedSoftwareVersion, const CString& updatedSoftwareVersion,
|
||||
const CParameterSet& parameterSet, const CString& shortDesc, const CString& detailedDesc)
|
||||
: m_ShortDesc(shortDesc), m_DetailedDesc(detailedDesc), m_DescClassID(descClassID), m_ClassID(classID),
|
||||
m_AddedSoftwareVersion(addedSoftwareVersion), m_UpdatedSoftwareVersion(updatedSoftwareVersion), m_Parameters(parameterSet)
|
||||
{
|
||||
const std::string fullname(name.toASCIIString());
|
||||
const size_t i = fullname.rfind('/');
|
||||
if (i != std::string::npos)
|
||||
{
|
||||
m_Name = CString(fullname.substr(i + 1).c_str());
|
||||
m_CategoryName = CString(fullname.substr(0, i).c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
m_Name = CString(name);
|
||||
m_CategoryName = CString("");
|
||||
}
|
||||
}
|
||||
|
||||
void release() override { }
|
||||
|
||||
CString getName() const override { return m_Name; }
|
||||
CString getAuthorName() const override { return CString("Yann Renard"); }
|
||||
CString getAuthorCompanyName() const override { return CString("Mensia Technologies SA"); }
|
||||
CString getShortDescription() const override { return m_ShortDesc; }
|
||||
CString getDetailedDescription() const override { return m_DetailedDesc; }
|
||||
// virtual OpenViBE::CString getCategory() const { return OpenViBE::CString(""); }
|
||||
CString getVersion() const override { return CString("1.0"); }
|
||||
CString getSoftwareComponent() const override { return "openvibe-designer"; }
|
||||
CString getAddedSoftwareVersion() const override { return m_AddedSoftwareVersion; }
|
||||
CString getUpdatedSoftwareVersion() const override { return m_UpdatedSoftwareVersion; }
|
||||
CString getStockItemName() const override { return CString("gtk-find"); }
|
||||
CIdentifier getCreatedClass() const override { return m_ClassID; }
|
||||
|
||||
void releaseBoxListener(Plugins::IBoxListener* listener) const override { delete listener; }
|
||||
|
||||
bool hasFunctionality(const Plugins::EPluginFunctionality functionality) const override
|
||||
{
|
||||
return functionality == Plugins::EPluginFunctionality::Visualization;
|
||||
}
|
||||
|
||||
bool getBoxPrototype(Kernel::IBoxProto& prototype) const override
|
||||
{
|
||||
for (auto p : m_Parameters)
|
||||
{
|
||||
if (p == I_Matrix) { prototype.addInput("Matrix", OV_TypeId_StreamedMatrix); }
|
||||
if (p == I_Signal) { prototype.addInput("Matrix", OV_TypeId_StreamedMatrix); } // This is later changed in the listener
|
||||
if (p == I_Spectrum) { prototype.addInput("Matrix", OV_TypeId_StreamedMatrix); } // This is later changed in the listener
|
||||
if (p == I_TimeFrequency) { prototype.addInput("Matrix", OV_TypeId_TimeFrequency); } // This is later changed in the listener
|
||||
if (p == I_Covariance) { prototype.addInput("Matrix", OV_TypeId_StreamedMatrix); } // This is later changed in the listener
|
||||
if (p == I_Stimulations) { prototype.addInput("Markers", OV_TypeId_Stimulations); }
|
||||
if (p == S_ChannelLocalisation
|
||||
)
|
||||
{
|
||||
prototype.addSetting("Channel Localisation", OV_TypeId_Filename, "${AdvancedViz_ChannelLocalisation}");
|
||||
} // "../share/electrode_sets/electrode_set_standard_cartesian.txt"
|
||||
if (p == S_DataPositive) { prototype.addSetting("Positive Data Only ?", OV_TypeId_Boolean, "false"); }
|
||||
if (p == S_TemporalCoherence) { prototype.addSetting("Temporal Coherence", OVP_TypeId_TemporalCoherence, "Time Locked"); }
|
||||
if (p == S_TimeScale) { prototype.addSetting("Time Scale", OV_TypeId_Float, "20"); }
|
||||
if (p == S_ElementCount) { prototype.addSetting("Matrix Count", OV_TypeId_Integer, "50"); }
|
||||
if (p == S_DataScale) { prototype.addSetting("Gain", OV_TypeId_Float, "1"); }
|
||||
if (p == S_Caption) { prototype.addSetting("Caption", OV_TypeId_String, ""); }
|
||||
if (p == S_FlowerRingCount) { prototype.addSetting("Flower Ring Count", OV_TypeId_Integer, "1"); }
|
||||
if (p == S_Translucency) { prototype.addSetting("Translucency", OV_TypeId_Float, "1"); }
|
||||
if (p == S_ShowAxis) { prototype.addSetting("Show Axis", OV_TypeId_Boolean, "true"); }
|
||||
if (p == S_XYZPlotHasDepth) { prototype.addSetting("Use third channel as depth", OV_TypeId_Boolean, "false"); } // XYZ Plot
|
||||
if (p == S_Color) { prototype.addSetting("Color", OV_TypeId_Color, "${AdvancedViz_DefaultColor}"); }
|
||||
if (p == S_ColorGradient) { prototype.addSetting("Color", OV_TypeId_ColorGradient, "${AdvancedViz_DefaultColorGradient}"); }
|
||||
if (p == F_CanAddInput) { prototype.addFlag(Kernel::BoxFlag_CanAddInput); }
|
||||
if (p == F_FixedChannelOrder) {} // prototype.addFlag(OpenViBE::Kernel::BoxFlag_);
|
||||
if (p == F_FixedChannelSelection) {} // prototype.addFlag(OpenViBE::Kernel::BoxFlag_);
|
||||
}
|
||||
prototype.addFlag(Kernel::BoxFlag_CanModifyInput);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
} // namespace AdvancedVisualization
|
||||
} // namespace OpenViBE
|
||||
+66
@@ -0,0 +1,66 @@
|
||||
/*********************************************************************
|
||||
* Software License Agreement (AGPL-3 License)
|
||||
*
|
||||
* OpenViBE Designer
|
||||
* Based on OpenViBE V1.1.0, Copyright (C) Inria, 2006-2015
|
||||
* Copyright (C) Inria, 2015-2017,V1.0
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "mCMouse.hpp"
|
||||
#include "mCBoxAlgorithmViz.hpp"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace AdvancedVisualization {
|
||||
|
||||
void CMouse::mouseButton(CRendererContext& ctx, const int x, const int y, const int button, const int status)
|
||||
{
|
||||
m_Buttons[button] = status;
|
||||
|
||||
if (m_Buttons[1] == 2)
|
||||
{
|
||||
ctx.setScaleVisibility(!ctx.getScaleVisibility());
|
||||
m_BoxAlgorithmViz.redrawTopLevelWindow();
|
||||
}
|
||||
|
||||
m_X = x;
|
||||
m_Y = y;
|
||||
}
|
||||
|
||||
void CMouse::mouseMotion(CRendererContext& ctx, const int x, const int y)
|
||||
{
|
||||
if (m_Buttons[3]) { ctx.scaleBy(powf(.99F, float(y - m_Y))); }
|
||||
if (m_Buttons[2]) { ctx.zoomBy(powf(.99F, float(y - m_Y))); }
|
||||
if (m_Buttons[1])
|
||||
{
|
||||
ctx.rotateByY(float(x - m_X) * .1F);
|
||||
ctx.rotateByX(float(y - m_Y) * .1F);
|
||||
}
|
||||
|
||||
m_X = x;
|
||||
m_Y = y;
|
||||
}
|
||||
|
||||
bool CMouse::hasButtonPressed()
|
||||
|
||||
{
|
||||
for (const auto& button : m_Buttons) { if (button.second) { return true; } }
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace AdvancedVisualization
|
||||
} // namespace OpenViBE
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
/*********************************************************************
|
||||
* Software License Agreement (AGPL-3 License)
|
||||
*
|
||||
* OpenViBE Designer
|
||||
* Based on OpenViBE V1.1.0, Copyright (C) Inria, 2006-2015
|
||||
* Copyright (C) Inria, 2015-2017,V1.0
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <mensia/advanced-visualization.hpp>
|
||||
|
||||
#include <map>
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace AdvancedVisualization {
|
||||
class CBoxAlgorithmViz;
|
||||
|
||||
class CMouse
|
||||
{
|
||||
public:
|
||||
|
||||
explicit CMouse(CBoxAlgorithmViz& boxAlgorithmViz) : m_BoxAlgorithmViz(boxAlgorithmViz) { }
|
||||
void mouseButton(CRendererContext& ctx, const int x, const int y, const int button, const int status);
|
||||
void mouseMotion(CRendererContext& ctx, const int x, const int y);
|
||||
bool hasButtonPressed();
|
||||
|
||||
|
||||
CBoxAlgorithmViz& m_BoxAlgorithmViz;
|
||||
std::map<int, int> m_Buttons;
|
||||
int m_X = 0;
|
||||
int m_Y = 0;
|
||||
};
|
||||
} // namespace AdvancedVisualization
|
||||
} // namespace OpenViBE
|
||||
+107
@@ -0,0 +1,107 @@
|
||||
/*********************************************************************
|
||||
* Software License Agreement (AGPL-3 License)
|
||||
*
|
||||
* OpenViBE Designer
|
||||
* Based on OpenViBE V1.1.0, Copyright (C) Inria, 2006-2015
|
||||
* Copyright (C) Inria, 2015-2017,V1.0
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <mensia/advanced-visualization.hpp>
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#if defined TARGET_OS_Windows
|
||||
#include <Windows.h>
|
||||
#endif
|
||||
|
||||
#include <GL/gl.h>
|
||||
#include <GL/glu.h>
|
||||
|
||||
#include <cmath>
|
||||
#include <vector>
|
||||
#include <cstdlib>
|
||||
|
||||
#define IRuler_SplitCount 5
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace AdvancedVisualization {
|
||||
class IRuler
|
||||
{
|
||||
public:
|
||||
|
||||
IRuler() { }
|
||||
IRuler(const IRuler&) = delete;
|
||||
virtual ~IRuler() = default;
|
||||
|
||||
virtual void setRendererContext(const CRendererContext* ctx) { m_rendererCtx = ctx; }
|
||||
virtual void setRenderer(const IRenderer* renderer) { m_renderer = renderer; }
|
||||
|
||||
virtual void doRender() { this->render(); }
|
||||
virtual void doRenderLeft(GtkWidget* widget) { if (m_rendererCtx->getScaleVisibility()) { this->renderLeft(widget); } }
|
||||
virtual void doRenderRight(GtkWidget* widget) { if (m_rendererCtx->getScaleVisibility()) { this->renderRight(widget); } }
|
||||
virtual void doRenderBottom(GtkWidget* widget) { if (m_rendererCtx->getScaleVisibility()) { this->renderBottom(widget); } }
|
||||
|
||||
protected:
|
||||
|
||||
virtual void render() { }
|
||||
virtual void renderLeft(GtkWidget* /*widget*/) { }
|
||||
virtual void renderRight(GtkWidget* /*widget*/) { }
|
||||
virtual void renderBottom(GtkWidget* /*widget*/) { }
|
||||
|
||||
std::vector<double> splitRange(const double start, const double stop, const size_t count = 10) const
|
||||
{
|
||||
std::vector<double> res;
|
||||
const double range = stop - start;
|
||||
const double order = floor(log(range) / log(10.) - .1F);
|
||||
double step = pow(10, order);
|
||||
double nStep = trunc(range / step);
|
||||
|
||||
while (nStep < count)
|
||||
{
|
||||
nStep *= 2;
|
||||
step /= 2;
|
||||
}
|
||||
while (nStep > count)
|
||||
{
|
||||
nStep /= 2;
|
||||
step *= 2;
|
||||
}
|
||||
|
||||
double value = trunc(start / step) * step;
|
||||
while (value < start) { value += step; }
|
||||
while (value <= stop)
|
||||
{
|
||||
res.push_back(std::abs(value) < std::abs(range / 1000) ? 0 : value);
|
||||
value += step;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static std::string getLabel(const double v)
|
||||
{
|
||||
char label[1024];
|
||||
(fabs(v) < 1E-10) ? sprintf(label, "0") : sprintf(label, "%g", v);
|
||||
return label;
|
||||
}
|
||||
|
||||
const CRendererContext* m_rendererCtx = nullptr;
|
||||
const IRenderer* m_renderer = nullptr;
|
||||
float m_blackAlpha = 0.9F;
|
||||
float m_whiteAlpha = 1.0F;
|
||||
};
|
||||
} // namespace AdvancedVisualization
|
||||
} // namespace OpenViBE
|
||||
+314
@@ -0,0 +1,314 @@
|
||||
/*********************************************************************
|
||||
* Software License Agreement (AGPL-3 License)
|
||||
*
|
||||
* OpenViBE Designer
|
||||
* Based on OpenViBE V1.1.0, Copyright (C) Inria, 2006-2015
|
||||
* Copyright (C) Inria, 2015-2017,V1.0
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "mCBoxAlgorithmViz.hpp"
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace AdvancedVisualization {
|
||||
template <class TRendererFactoryClass, class TRulerClass>
|
||||
class TBoxAlgorithmContinuousViz final : public CBoxAlgorithmViz
|
||||
{
|
||||
public:
|
||||
|
||||
TBoxAlgorithmContinuousViz(const CIdentifier& classID, const std::vector<int>& parameters);
|
||||
bool initialize() override;
|
||||
bool uninitialize() override;
|
||||
bool process() override;
|
||||
|
||||
_IsDerivedFromClass_Final_(CBoxAlgorithmViz, m_ClassID)
|
||||
|
||||
Toolkit::TStreamedMatrixDecoder<TBoxAlgorithmContinuousViz<TRendererFactoryClass, TRulerClass>> m_oMatrixDecoder;
|
||||
Toolkit::TStimulationDecoder<TBoxAlgorithmContinuousViz<TRendererFactoryClass, TRulerClass>> m_oStimulationDecoder;
|
||||
TRendererFactoryClass m_RendererFactory;
|
||||
IRenderer* m_Renderer = nullptr;
|
||||
|
||||
protected:
|
||||
|
||||
void draw() override;
|
||||
};
|
||||
|
||||
class CBoxAlgorithmContinuousVizListener final : public CBoxAlgorithmVizListener
|
||||
{
|
||||
public:
|
||||
|
||||
explicit CBoxAlgorithmContinuousVizListener(const std::vector<int>& parameters) : CBoxAlgorithmVizListener(parameters) { }
|
||||
|
||||
bool onInputTypeChanged(Kernel::IBox& box, const size_t index) override
|
||||
{
|
||||
CIdentifier typeID = CIdentifier::undefined();
|
||||
box.getInputType(index, typeID);
|
||||
if (!this->getTypeManager().isDerivedFromStream(typeID, OV_TypeId_StreamedMatrix)) { box.setInputType(index, OV_TypeId_StreamedMatrix); }
|
||||
box.setInputType(1, OV_TypeId_Stimulations);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
template <class TRendererFactoryClass, class TRulerClass = IRuler>
|
||||
class TBoxAlgorithmContinuousVizDesc final : public CBoxAlgorithmVizDesc
|
||||
{
|
||||
public:
|
||||
|
||||
TBoxAlgorithmContinuousVizDesc(const CString& name, const CIdentifier& descClassID, const CIdentifier& classID,
|
||||
const CString& addedSoftwareVersion, const CString& updatedSoftwareVersion,
|
||||
const CParameterSet& parameterSet, const CString& shortDesc, const CString& detailedDesc)
|
||||
: CBoxAlgorithmVizDesc(name, descClassID, classID, addedSoftwareVersion, updatedSoftwareVersion, parameterSet, shortDesc, detailedDesc) { }
|
||||
|
||||
Plugins::IPluginObject* create() override { return new TBoxAlgorithmContinuousViz<TRendererFactoryClass, TRulerClass>(m_ClassID, m_Parameters); }
|
||||
Plugins::IBoxListener* createBoxListener() const override { return new CBoxAlgorithmContinuousVizListener(m_Parameters); }
|
||||
CString getCategory() const override { return CString("Advanced Visualization/") + m_CategoryName; }
|
||||
|
||||
_IsDerivedFromClass_Final_(OpenViBE::Plugins::IBoxAlgorithmDesc, m_DescClassID)
|
||||
};
|
||||
|
||||
template <class TRendererFactoryClass, class TRulerClass>
|
||||
TBoxAlgorithmContinuousViz<TRendererFactoryClass, TRulerClass>::TBoxAlgorithmContinuousViz(
|
||||
const CIdentifier& classID, const std::vector<int>& parameters) : CBoxAlgorithmViz(classID, parameters) { }
|
||||
|
||||
template <class TRendererFactoryClass, class TRulerClass>
|
||||
bool TBoxAlgorithmContinuousViz<TRendererFactoryClass, TRulerClass>::initialize()
|
||||
{
|
||||
const bool res = CBoxAlgorithmViz::initialize();
|
||||
|
||||
m_oMatrixDecoder.initialize(*this, 0);
|
||||
m_oStimulationDecoder.initialize(*this, 1);
|
||||
|
||||
m_Renderer = m_RendererFactory.create();
|
||||
|
||||
m_Ruler = new TRulerClass;
|
||||
m_Ruler->setRendererContext(m_RendererCtx);
|
||||
m_Ruler->setRenderer(m_Renderer);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
template <class TRendererFactoryClass, class TRulerClass>
|
||||
bool TBoxAlgorithmContinuousViz<TRendererFactoryClass, TRulerClass>::uninitialize()
|
||||
{
|
||||
m_RendererFactory.release(m_Renderer);
|
||||
m_Renderer = nullptr;
|
||||
|
||||
delete m_Ruler;
|
||||
m_Ruler = nullptr;
|
||||
|
||||
m_oStimulationDecoder.uninitialize();
|
||||
m_oMatrixDecoder.uninitialize();
|
||||
|
||||
return CBoxAlgorithmViz::uninitialize();
|
||||
}
|
||||
|
||||
template <class TRendererFactoryClass, class TRulerClass>
|
||||
bool TBoxAlgorithmContinuousViz<TRendererFactoryClass, TRulerClass>::process()
|
||||
{
|
||||
Kernel::IBoxIO& boxContext = this->getDynamicBoxContext();
|
||||
for (size_t i = 0; i < boxContext.getInputChunkCount(0); ++i)
|
||||
{
|
||||
m_oMatrixDecoder.decode(i);
|
||||
|
||||
CMatrix* matrix = m_oMatrixDecoder.getOutputMatrix();
|
||||
size_t nChannel = matrix->getDimensionSize(0);
|
||||
size_t nSample = matrix->getDimensionSize(1);
|
||||
|
||||
if (nChannel == 0)
|
||||
{
|
||||
this->getLogManager() << Kernel::LogLevel_Error << "Input stream " << i << " has 0 channels\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (matrix->getDimensionCount() == 1)
|
||||
{
|
||||
nChannel = matrix->getDimensionSize(0);
|
||||
nSample = 1;
|
||||
}
|
||||
|
||||
if (m_oMatrixDecoder.isHeaderReceived())
|
||||
{
|
||||
GtkTreeIter gtkTreeIt;
|
||||
gtk_list_store_clear(m_ChannelListStore);
|
||||
|
||||
m_Swaps.resize(size_t(nChannel));
|
||||
|
||||
m_RendererCtx->clear();
|
||||
m_RendererCtx->setTranslucency(float(m_Translucency));
|
||||
m_RendererCtx->setFlowerRingCount(m_NFlowerRing);
|
||||
m_RendererCtx->setTimeScale(m_TimeScale);
|
||||
m_RendererCtx->setElementCount(m_NElement);
|
||||
m_RendererCtx->scaleBy(float(m_DataScale));
|
||||
m_RendererCtx->setAxisDisplay(m_ShowAxis);
|
||||
m_RendererCtx->setPositiveOnly(m_IsPositive);
|
||||
m_RendererCtx->setParentRendererContext(&getContext());
|
||||
m_RendererCtx->setTimeLocked(m_IsTimeLocked);
|
||||
m_RendererCtx->setXYZPlotDepth(m_XYZPlotHasDepth);
|
||||
|
||||
gtk_tree_view_set_model(m_ChannelTreeView, nullptr);
|
||||
for (size_t j = 0; j < nChannel; ++j)
|
||||
{
|
||||
std::string name = trim(matrix->getDimensionLabel(0, j));
|
||||
std::string subname = name;
|
||||
std::transform(name.begin(), name.end(), subname.begin(), tolower);
|
||||
const CVertex v = m_ChannelPositions[subname];
|
||||
|
||||
if (name.empty()) { name = "Channel " + std::to_string(j + 1); }
|
||||
|
||||
m_RendererCtx->addChannel(name, v.x, v.y, v.z);
|
||||
gtk_list_store_append(m_ChannelListStore, >kTreeIt);
|
||||
gtk_list_store_set(m_ChannelListStore, >kTreeIt, 0, j + 1, 1, name.c_str(), -1);
|
||||
}
|
||||
gtk_tree_view_set_model(m_ChannelTreeView, GTK_TREE_MODEL(m_ChannelListStore));
|
||||
gtk_tree_selection_select_all(gtk_tree_view_get_selection(m_ChannelTreeView));
|
||||
|
||||
m_Renderer->setChannelCount(nChannel);
|
||||
|
||||
if (m_TypeID == OV_TypeId_Signal) { m_RendererCtx->setDataType(CRendererContext::EDataType::Signal); }
|
||||
else if (m_TypeID == OV_TypeId_Spectrum) { m_RendererCtx->setDataType(CRendererContext::EDataType::Spectrum); }
|
||||
else { m_RendererCtx->setDataType(CRendererContext::EDataType::Matrix); }
|
||||
|
||||
if (nSample != 1)
|
||||
{
|
||||
//bool warned = false;
|
||||
if (m_TypeID == OV_TypeId_Spectrum)
|
||||
{
|
||||
//warned = true;
|
||||
this->getLogManager() << Kernel::LogLevel_Warning << "Input matrix has 'spectrum' type\n";
|
||||
this->getLogManager() << Kernel::LogLevel_Warning << "Such configuration is uncommon for a 'continous' kind of visualization !\n";
|
||||
this->getLogManager() << Kernel::LogLevel_Warning <<
|
||||
"You might want to consider the 'stacked' kind of visualization for time/frequency analysis for instance\n";
|
||||
this->getLogManager() << Kernel::LogLevel_Warning << "Please double check your scenario\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!m_RendererCtx->isTimeLocked())
|
||||
{
|
||||
//warned = true;
|
||||
this->getLogManager() << Kernel::LogLevel_Warning << "Input matrix has " << nSample
|
||||
<< " elements and the box settings say the elements are independant with " << m_NElement << " elements to render\n";
|
||||
this->getLogManager() << Kernel::LogLevel_Warning <<
|
||||
"Such configuration is uncommon for a 'continous' kind of visualization !\n";
|
||||
this->getLogManager() << Kernel::LogLevel_Warning << "You might want either of the following alternative :\n";
|
||||
this->getLogManager() << Kernel::LogLevel_Warning << " - an 'instant' kind of visualization to highlight the " << m_NElement
|
||||
<< " elements of the matrix\n";
|
||||
this->getLogManager() << Kernel::LogLevel_Warning <<
|
||||
" - a 'time locked' kind of elements (thus the scenario must refresh the matrix on a regular basis)\n";
|
||||
this->getLogManager() << Kernel::LogLevel_Warning << "Please double check your scenario and box settings\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_RebuildNeeded = true;
|
||||
m_RefreshNeeded = true;
|
||||
m_RedrawNeeded = true;
|
||||
}
|
||||
if (m_oMatrixDecoder.isBufferReceived())
|
||||
{
|
||||
m_Time1 = m_Time2;
|
||||
m_Time2 = boxContext.getInputChunkEndTime(0, i);
|
||||
const uint64_t duration = (m_Time2 - m_Time1) / nSample;
|
||||
if ((duration & ~0xf) != (m_RendererCtx->getSampleDuration() & ~0xf) && duration != 0) // 0xf mask avoids rounding errors
|
||||
{
|
||||
m_RendererCtx->setSampleDuration(duration);
|
||||
}
|
||||
m_RendererCtx->setSpectrumFrequencyRange(
|
||||
size_t((uint64_t(nSample) << 32) / (boxContext.getInputChunkEndTime(0, i) - boxContext.getInputChunkStartTime(0, i))));
|
||||
m_RendererCtx->setMinimumSpectrumFrequency(size_t(gtk_spin_button_get_value(GTK_SPIN_BUTTON(m_FrequencyBandMin))));
|
||||
m_RendererCtx->setMaximumSpectrumFrequency(size_t(gtk_spin_button_get_value(GTK_SPIN_BUTTON(m_FrequencyBandMax))));
|
||||
|
||||
// Feed renderer with actual samples
|
||||
for (size_t j = 0; j < nSample; ++j)
|
||||
{
|
||||
for (size_t k = 0; k < nChannel; ++k) { m_Swaps[k] = float(matrix->getBuffer()[k * nSample + j]); }
|
||||
m_Renderer->feed(&m_Swaps[0]);
|
||||
}
|
||||
|
||||
// Adjust feeding depending on theoretical dates
|
||||
if (m_RendererCtx->isTimeLocked() && m_RendererCtx->getSampleDuration())
|
||||
{
|
||||
const auto nTheoreticalSample = size_t(m_Time2 / m_RendererCtx->getSampleDuration());
|
||||
if (nTheoreticalSample > m_Renderer->getHistoryCount()) { m_Renderer->prefeed(nTheoreticalSample - m_Renderer->getHistoryCount()); }
|
||||
}
|
||||
|
||||
m_RefreshNeeded = true;
|
||||
m_RedrawNeeded = true;
|
||||
}
|
||||
}
|
||||
|
||||
const size_t nInput = this->getStaticBoxContext().getInputCount();
|
||||
if (nInput > 1)
|
||||
{
|
||||
for (size_t i = 0; i < boxContext.getInputChunkCount(1); ++i)
|
||||
{
|
||||
m_oStimulationDecoder.decode(i);
|
||||
if (m_oStimulationDecoder.isBufferReceived())
|
||||
{
|
||||
IStimulationSet* stimulationSet = m_oStimulationDecoder.getOutputStimulationSet();
|
||||
for (size_t j = 0; j < stimulationSet->getStimulationCount(); ++j)
|
||||
{
|
||||
m_Renderer->feed(stimulationSet->getStimulationDate(j), stimulationSet->getStimulationIdentifier(j));
|
||||
m_RedrawNeeded = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
size_t rendererSampleCount = 0;
|
||||
if (m_RendererCtx->isTimeLocked())
|
||||
{
|
||||
if (0 != m_RendererCtx->getSampleDuration()) { rendererSampleCount = size_t(m_RendererCtx->getTimeScale() / m_RendererCtx->getSampleDuration()); }
|
||||
}
|
||||
else
|
||||
{
|
||||
rendererSampleCount = size_t(m_RendererCtx->getElementCount()); // *nSample;
|
||||
}
|
||||
|
||||
if (rendererSampleCount != 0 && rendererSampleCount != m_Renderer->getSampleCount())
|
||||
{
|
||||
m_Renderer->setSampleCount(rendererSampleCount);
|
||||
m_RebuildNeeded = true;
|
||||
m_RefreshNeeded = true;
|
||||
m_RedrawNeeded = true;
|
||||
}
|
||||
|
||||
if (m_RebuildNeeded) { m_Renderer->rebuild(*m_RendererCtx); }
|
||||
if (m_RefreshNeeded) { m_Renderer->refresh(*m_RendererCtx); }
|
||||
if (m_RedrawNeeded) { this->redraw(); }
|
||||
|
||||
m_RebuildNeeded = false;
|
||||
m_RefreshNeeded = false;
|
||||
m_RedrawNeeded = false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class TRendererFactoryClass, class TRulerClass>
|
||||
void TBoxAlgorithmContinuousViz<TRendererFactoryClass, TRulerClass>::draw()
|
||||
|
||||
{
|
||||
CBoxAlgorithmViz::preDraw();
|
||||
|
||||
glPushAttrib(GL_ALL_ATTRIB_BITS);
|
||||
glColor4f(m_Color.r, m_Color.g, m_Color.b, m_RendererCtx->getTranslucency());
|
||||
m_Renderer->render(*m_RendererCtx);
|
||||
glPopAttrib();
|
||||
|
||||
CBoxAlgorithmViz::postDraw();
|
||||
}
|
||||
} // namespace AdvancedVisualization
|
||||
} // namespace OpenViBE
|
||||
+123
@@ -0,0 +1,123 @@
|
||||
/*********************************************************************
|
||||
* Software License Agreement (AGPL-3 License)
|
||||
*
|
||||
* OpenViBE Designer
|
||||
* Based on OpenViBE V1.1.0, Copyright (C) Inria, 2006-2015
|
||||
* Copyright (C) Inria, 2015-2017,V1.0
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "mTBoxAlgorithmInstantViz.hpp"
|
||||
#include <array>
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace AdvancedVisualization {
|
||||
template <class TRendererFactoryClass, class TRulerClass>
|
||||
class TBoxAlgorithmInstantLoretaViz final : public TBoxAlgorithmInstantViz<TRendererFactoryClass, TRulerClass>
|
||||
{
|
||||
public:
|
||||
|
||||
TBoxAlgorithmInstantLoretaViz(const CIdentifier& classID, const std::vector<int>& parameters)
|
||||
: TBoxAlgorithmInstantViz<TRendererFactoryClass, TRulerClass>(classID, parameters) { }
|
||||
|
||||
static void callback(GtkTreeSelection* selection, TBoxAlgorithmInstantLoretaViz<TRendererFactoryClass, TRulerClass>* box)
|
||||
{
|
||||
box->regionSelectionChanged(selection);
|
||||
}
|
||||
|
||||
void regionSelectionChanged(GtkTreeSelection* pTreeSelection)
|
||||
{
|
||||
m_Renderer->clearRegionSelection();
|
||||
|
||||
GtkTreeIter iter;
|
||||
|
||||
char* value = nullptr;
|
||||
for (size_t i = 0; i < 3; ++i)
|
||||
{
|
||||
GtkTreeSelection* selection = gtk_tree_view_get_selection(m_LookupTreeView[i]);
|
||||
|
||||
if (selection == pTreeSelection)
|
||||
{
|
||||
if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(m_LookupListStore[i]), &iter))
|
||||
{
|
||||
do
|
||||
{
|
||||
if (gtk_tree_selection_iter_is_selected(selection, &iter))
|
||||
{
|
||||
gtk_tree_model_get(GTK_TREE_MODEL(m_LookupListStore[i]), &iter, 0, &value, -1);
|
||||
m_Renderer->selectRegion(i, value);
|
||||
}
|
||||
} while (gtk_tree_model_iter_next(GTK_TREE_MODEL(m_LookupListStore[i]), &iter));
|
||||
}
|
||||
}
|
||||
else { gtk_tree_selection_unselect_all(selection); }
|
||||
}
|
||||
}
|
||||
|
||||
void fillRegion(GtkListStore* listStore, GtkTreeView* view, IRenderer* renderer, const size_t category) const
|
||||
{
|
||||
GtkTreeIter gtkTreeIter;
|
||||
|
||||
gtk_list_store_clear(listStore);
|
||||
gtk_tree_selection_set_mode(gtk_tree_view_get_selection(view), GTK_SELECTION_MULTIPLE);
|
||||
for (size_t i = 0; i < renderer->getRegionCount(category); ++i)
|
||||
{
|
||||
const char* name = m_Renderer->getRegionName(category, i);
|
||||
gtk_list_store_append((listStore), >kTreeIter);
|
||||
gtk_list_store_set(listStore, >kTreeIter, 0, name ? name : "", -1);
|
||||
gtk_tree_selection_select_iter(gtk_tree_view_get_selection(view), >kTreeIter);
|
||||
}
|
||||
}
|
||||
|
||||
using TBoxAlgorithmInstantViz<TRendererFactoryClass, TRulerClass>::m_Renderers;
|
||||
using TBoxAlgorithmInstantViz<TRendererFactoryClass, TRulerClass>::m_Builder;
|
||||
|
||||
bool initialize() override
|
||||
|
||||
{
|
||||
TBoxAlgorithmInstantViz<TRendererFactoryClass, TRulerClass>::initialize();
|
||||
|
||||
m_Renderer = m_Renderers[0];
|
||||
|
||||
gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(m_Builder, "expander_select")));
|
||||
gtk_widget_show(GTK_WIDGET(gtk_builder_get_object(m_Builder, "expander_select_sLORETA")));
|
||||
|
||||
m_LookupTreeView[0] = GTK_TREE_VIEW(gtk_builder_get_object(m_Builder, "expander_select_broadmann_treeview"));
|
||||
m_LookupTreeView[1] = GTK_TREE_VIEW(gtk_builder_get_object(m_Builder, "expander_select_neuro_1_treeview"));
|
||||
m_LookupTreeView[2] = GTK_TREE_VIEW(gtk_builder_get_object(m_Builder, "expander_select_neuro_2_treeview"));
|
||||
m_LookupListStore[0] = GTK_LIST_STORE(gtk_builder_get_object(m_Builder, "liststore_select_broadmann"));
|
||||
m_LookupListStore[1] = GTK_LIST_STORE(gtk_builder_get_object(m_Builder, "liststore_select_neuro_1"));
|
||||
m_LookupListStore[2] = GTK_LIST_STORE(gtk_builder_get_object(m_Builder, "liststore_select_neuro_2"));
|
||||
|
||||
for (size_t i = 0; i < m_Renderer->getRegionCategoryCount() && i < 3; ++i)
|
||||
{
|
||||
this->fillRegion(m_LookupListStore[i], m_LookupTreeView[i], m_Renderer, i);
|
||||
}
|
||||
|
||||
g_signal_connect(gtk_tree_view_get_selection(m_LookupTreeView[0]), "changed", G_CALLBACK(callback), this);
|
||||
g_signal_connect(gtk_tree_view_get_selection(m_LookupTreeView[1]), "changed", G_CALLBACK(callback), this);
|
||||
g_signal_connect(gtk_tree_view_get_selection(m_LookupTreeView[2]), "changed", G_CALLBACK(callback), this);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
IRenderer* m_Renderer = nullptr;
|
||||
std::array<GtkTreeView*, 3> m_LookupTreeView{};
|
||||
std::array<GtkListStore*, 3> m_LookupListStore{};
|
||||
};
|
||||
} // namespace AdvancedVisualization
|
||||
} // namespace OpenViBE
|
||||
+304
@@ -0,0 +1,304 @@
|
||||
/*********************************************************************
|
||||
* Software License Agreement (AGPL-3 License)
|
||||
*
|
||||
* OpenViBE Designer
|
||||
* Based on OpenViBE V1.1.0, Copyright (C) Inria, 2006-2015
|
||||
* Copyright (C) Inria, 2015-2017,V1.0
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "mCBoxAlgorithmViz.hpp"
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace AdvancedVisualization {
|
||||
template <class TRendererFactoryClass, class TRulerClass>
|
||||
class TBoxAlgorithmInstantViz : public CBoxAlgorithmViz
|
||||
{
|
||||
public:
|
||||
|
||||
TBoxAlgorithmInstantViz(const CIdentifier& classID, const std::vector<int>& params);
|
||||
bool initialize() override;
|
||||
bool uninitialize() override;
|
||||
bool process() override;
|
||||
|
||||
_IsDerivedFromClass_Final_(CBoxAlgorithmViz, m_ClassID)
|
||||
|
||||
TRendererFactoryClass m_RendererFactory;
|
||||
|
||||
size_t m_NInput = 0;
|
||||
std::vector<IRenderer*> m_Renderers;
|
||||
std::vector<Toolkit::TStreamedMatrixDecoder<TBoxAlgorithmInstantViz<TRendererFactoryClass, TRulerClass>>> m_Decoder;
|
||||
|
||||
double m_LastERPFraction = 0;
|
||||
|
||||
protected:
|
||||
|
||||
void draw() override;
|
||||
};
|
||||
|
||||
class CBoxAlgorithmInstantVizListener final : public CBoxAlgorithmVizListener
|
||||
{
|
||||
public:
|
||||
|
||||
explicit CBoxAlgorithmInstantVizListener(const std::vector<int>& parameters) : CBoxAlgorithmVizListener(parameters) { }
|
||||
|
||||
bool onInputTypeChanged(Kernel::IBox& box, const size_t index) override
|
||||
{
|
||||
CIdentifier typeID = CIdentifier::undefined();
|
||||
box.getInputType(index, typeID);
|
||||
if (!this->getTypeManager().isDerivedFromStream(typeID, OV_TypeId_StreamedMatrix)) { box.setInputType(index, OV_TypeId_StreamedMatrix); }
|
||||
else { for (size_t i = 0; i < box.getInputCount(); ++i) { box.setInputType(i, typeID); } }
|
||||
return true;
|
||||
}
|
||||
|
||||
bool onInputAdded(Kernel::IBox& box, const size_t index) override
|
||||
{
|
||||
CIdentifier typeID = CIdentifier::undefined();
|
||||
box.getInputType(0, typeID);
|
||||
box.setInputType(index, typeID);
|
||||
box.setInputName(index, "Matrix");
|
||||
box.addSetting("Color", OV_TypeId_Color, "${AdvancedViz_DefaultColor}");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool onInputRemoved(Kernel::IBox& box, const size_t index) override
|
||||
{
|
||||
box.removeSetting(this->getBaseSettingCount() + index - 1);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
template <class TRendererFactoryClass, class TRulerClass = IRuler, template < typename, typename > class TBoxAlgorithm = TBoxAlgorithmInstantViz>
|
||||
class TBoxAlgorithmInstantVizDesc : public CBoxAlgorithmVizDesc
|
||||
{
|
||||
public:
|
||||
|
||||
TBoxAlgorithmInstantVizDesc(const CString& name, const CIdentifier& descClassID, const CIdentifier& classID,
|
||||
const CString& addedSoftwareVersion, const CString& updatedSoftwareVersion,
|
||||
const CParameterSet& parameterSet, const CString& shortDesc, const CString& detailedDesc)
|
||||
: CBoxAlgorithmVizDesc(name, descClassID, classID, addedSoftwareVersion, updatedSoftwareVersion, parameterSet, shortDesc, detailedDesc) { }
|
||||
|
||||
Plugins::IPluginObject* create() override { return new TBoxAlgorithm<TRendererFactoryClass, TRulerClass>(m_ClassID, m_Parameters); }
|
||||
Plugins::IBoxListener* createBoxListener() const override { return new CBoxAlgorithmInstantVizListener(m_Parameters); }
|
||||
CString getCategory() const override { return CString("Advanced Visualization/") + m_CategoryName; }
|
||||
|
||||
_IsDerivedFromClass_Final_(OpenViBE::Plugins::IBoxAlgorithmDesc, m_DescClassID)
|
||||
};
|
||||
|
||||
|
||||
template <class TRendererFactoryClass, class TRulerClass>
|
||||
TBoxAlgorithmInstantViz<TRendererFactoryClass, TRulerClass>::TBoxAlgorithmInstantViz(const CIdentifier& classID, const std::vector<int>& params)
|
||||
: CBoxAlgorithmViz(classID, params) { }
|
||||
|
||||
template <class TRendererFactoryClass, class TRulerClass>
|
||||
bool TBoxAlgorithmInstantViz<TRendererFactoryClass, TRulerClass>::initialize()
|
||||
{
|
||||
bool res = CBoxAlgorithmViz::initialize();
|
||||
|
||||
m_LastERPFraction = 0;
|
||||
|
||||
m_NInput = this->getStaticBoxContext().getInputCount();
|
||||
m_Renderers.resize(m_NInput);
|
||||
m_Decoder.resize(m_NInput);
|
||||
for (size_t i = 0; i < m_NInput; ++i)
|
||||
{
|
||||
m_Renderers[i] = m_RendererFactory.create();
|
||||
m_Decoder[i].initialize(*this, i);
|
||||
if (!m_Renderers[i])
|
||||
{
|
||||
this->getLogManager() << Kernel::LogLevel_Error << "Could not create renderer, it might have been disabled at compile time\n";
|
||||
res = false;
|
||||
}
|
||||
}
|
||||
|
||||
m_Ruler = new TRulerClass;
|
||||
m_Ruler->setRendererContext(m_RendererCtx);
|
||||
m_Ruler->setRenderer(m_Renderers[0]);
|
||||
|
||||
gtk_widget_set_sensitive(m_TimeScaleW, false);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
template <class TRendererFactoryClass, class TRulerClass>
|
||||
bool TBoxAlgorithmInstantViz<TRendererFactoryClass, TRulerClass>::uninitialize()
|
||||
{
|
||||
for (size_t i = 0; i < m_NInput; ++i)
|
||||
{
|
||||
m_RendererFactory.release(m_Renderers[i]);
|
||||
m_Decoder[i].uninitialize();
|
||||
}
|
||||
|
||||
m_Decoder.clear();
|
||||
m_Renderers.clear();
|
||||
|
||||
return CBoxAlgorithmViz::uninitialize();
|
||||
}
|
||||
|
||||
template <class TRendererFactoryClass, class TRulerClass>
|
||||
bool TBoxAlgorithmInstantViz<TRendererFactoryClass, TRulerClass>::process()
|
||||
|
||||
{
|
||||
Kernel::IBoxIO& boxContext = this->getDynamicBoxContext();
|
||||
const size_t nInput = this->getStaticBoxContext().getInputCount();
|
||||
|
||||
for (size_t i = 0; i < nInput; ++i)
|
||||
{
|
||||
for (size_t j = 0; j < boxContext.getInputChunkCount(i); ++j)
|
||||
{
|
||||
m_Decoder[i].decode(j);
|
||||
|
||||
CMatrix* matrix = m_Decoder[i].getOutputMatrix();
|
||||
size_t nChannel = matrix->getDimensionSize(0);
|
||||
size_t nSample = matrix->getDimensionSize(1);
|
||||
|
||||
if (nChannel == 0)
|
||||
{
|
||||
this->getLogManager() << Kernel::LogLevel_Error << "Input stream " << i << " has 0 channels\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (matrix->getDimensionCount() == 1)
|
||||
{
|
||||
nChannel = 1;
|
||||
nSample = matrix->getDimensionSize(0);
|
||||
}
|
||||
|
||||
if (m_Decoder[i].isHeaderReceived())
|
||||
{
|
||||
// TODO
|
||||
// Check dimension coherence
|
||||
// Only apply renderer context when first header is received
|
||||
|
||||
GtkTreeIter gtkTreeIter;
|
||||
gtk_list_store_clear(m_ChannelListStore);
|
||||
|
||||
m_Swaps.resize(nChannel);
|
||||
|
||||
m_RendererCtx->clear();
|
||||
m_RendererCtx->setTranslucency(float(m_Translucency));
|
||||
m_RendererCtx->setFlowerRingCount(m_NFlowerRing);
|
||||
// m_rendererCtx->setTimeScale(1); // Won't be used
|
||||
m_RendererCtx->scaleBy(float(m_DataScale));
|
||||
m_RendererCtx->setPositiveOnly(m_IsPositive);
|
||||
m_RendererCtx->setAxisDisplay(m_ShowAxis);
|
||||
m_RendererCtx->setParentRendererContext(&getContext());
|
||||
m_RendererCtx->setXYZPlotDepth(m_XYZPlotHasDepth);
|
||||
|
||||
gtk_tree_view_set_model(m_ChannelTreeView, nullptr);
|
||||
for (j = 0; j < nChannel; ++j)
|
||||
{
|
||||
std::string name = trim(matrix->getDimensionLabel(0, j));
|
||||
std::string subname = name;
|
||||
std::transform(name.begin(), name.end(), subname.begin(), tolower);
|
||||
const CVertex v = m_ChannelPositions[subname];
|
||||
|
||||
if (name.empty()) { name = "Channel " + std::to_string(j + 1); }
|
||||
|
||||
m_RendererCtx->addChannel(name, v.x, v.y, v.z);
|
||||
gtk_list_store_append(m_ChannelListStore, >kTreeIter);
|
||||
gtk_list_store_set(m_ChannelListStore, >kTreeIter, 0, j + 1, 1, name.c_str(), -1);
|
||||
}
|
||||
gtk_tree_view_set_model(m_ChannelTreeView, GTK_TREE_MODEL(m_ChannelListStore));
|
||||
gtk_tree_selection_select_all(gtk_tree_view_get_selection(m_ChannelTreeView));
|
||||
|
||||
m_Renderers[i]->setChannelCount(nChannel);
|
||||
m_Renderers[i]->setSampleCount(nSample);
|
||||
|
||||
if (nSample > 1 && m_TypeID != OV_TypeId_Spectrum) { gtk_widget_show(m_ERPPlayer); }
|
||||
|
||||
if (m_TypeID == OV_TypeId_Signal) { m_RendererCtx->setDataType(CRendererContext::EDataType::Signal); }
|
||||
else if (m_TypeID == OV_TypeId_Spectrum) { m_RendererCtx->setDataType(CRendererContext::EDataType::Spectrum); }
|
||||
else { m_RendererCtx->setDataType(CRendererContext::EDataType::Matrix); }
|
||||
|
||||
m_RebuildNeeded = true;
|
||||
m_RefreshNeeded = true;
|
||||
m_RedrawNeeded = true;
|
||||
}
|
||||
if (m_Decoder[i].isBufferReceived())
|
||||
{
|
||||
const uint64_t chunkDuration = (boxContext.getInputChunkEndTime(i, j) - boxContext.getInputChunkStartTime(i, j));
|
||||
|
||||
m_RendererCtx->setSampleDuration(chunkDuration / nSample);
|
||||
m_RendererCtx->setSpectrumFrequencyRange(size_t((uint64_t(nSample) << 32) / chunkDuration));
|
||||
m_RendererCtx->setMinimumSpectrumFrequency(size_t(gtk_spin_button_get_value(GTK_SPIN_BUTTON(m_FrequencyBandMin))));
|
||||
m_RendererCtx->setMaximumSpectrumFrequency(size_t(gtk_spin_button_get_value(GTK_SPIN_BUTTON(m_FrequencyBandMax))));
|
||||
|
||||
// Sets time scale
|
||||
gtk_spin_button_set_value(
|
||||
GTK_SPIN_BUTTON(gtk_builder_get_object(m_Builder, "spinbutton_time_scale")), (chunkDuration >> 22) / 1024.);
|
||||
|
||||
m_Renderers[i]->clear(0); // Drop last samples as they will be fed again
|
||||
for (size_t k = 0; k < nSample; ++k)
|
||||
{
|
||||
for (size_t l = 0; l < nChannel; ++l) { m_Swaps[l] = float(matrix->getBuffer()[l * nSample + k]); }
|
||||
m_Renderers[i]->feed(&m_Swaps[0]);
|
||||
}
|
||||
|
||||
m_RefreshNeeded = true;
|
||||
m_RedrawNeeded = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
double erpFraction = getContext().getERPFraction();
|
||||
if (m_RendererCtx->isERPPlayerActive())
|
||||
{
|
||||
erpFraction += .0025;
|
||||
if (erpFraction > 1) { erpFraction = 0; }
|
||||
}
|
||||
if (m_LastERPFraction != erpFraction)
|
||||
{
|
||||
gtk_range_set_value(GTK_RANGE(m_ERPRange), erpFraction);
|
||||
m_LastERPFraction = erpFraction;
|
||||
m_RefreshNeeded = true;
|
||||
m_RedrawNeeded = true;
|
||||
}
|
||||
|
||||
if (m_RebuildNeeded) { for (auto& renderer : m_Renderers) { renderer->rebuild(*m_RendererCtx); } }
|
||||
if (m_RefreshNeeded) { for (auto& renderer : m_Renderers) { renderer->refresh(*m_RendererCtx); } }
|
||||
if (m_RedrawNeeded) { this->redraw(); }
|
||||
|
||||
m_RebuildNeeded = false;
|
||||
m_RefreshNeeded = false;
|
||||
m_RedrawNeeded = false;
|
||||
|
||||
if (m_RendererCtx->isERPPlayerActive()) { gtk_button_set_label(GTK_BUTTON(m_ERPPlayerButton), GTK_STOCK_MEDIA_PAUSE); }
|
||||
else { gtk_button_set_label(GTK_BUTTON(m_ERPPlayerButton), GTK_STOCK_MEDIA_PLAY); }
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class TRendererFactoryClass, class TRulerClass>
|
||||
void TBoxAlgorithmInstantViz<TRendererFactoryClass, TRulerClass>::draw()
|
||||
|
||||
{
|
||||
CBoxAlgorithmViz::preDraw();
|
||||
|
||||
for (size_t i = 0; i < m_NInput; ++i)
|
||||
{
|
||||
glPushAttrib(GL_ALL_ATTRIB_BITS);
|
||||
if (i < m_Colors.size()) { glColor4f(m_Colors[i].r, m_Colors[i].g, m_Colors[i].b, m_RendererCtx->getTranslucency()); }
|
||||
else { glColor4f(m_Color.r, m_Color.g, m_Color.b, m_RendererCtx->getTranslucency()); }
|
||||
if (m_Renderers[i]) { m_Renderers[i]->render(*m_RendererCtx); }
|
||||
glPopAttrib();
|
||||
}
|
||||
|
||||
CBoxAlgorithmViz::postDraw();
|
||||
}
|
||||
} // namespace AdvancedVisualization
|
||||
} // namespace OpenViBE
|
||||
+392
@@ -0,0 +1,392 @@
|
||||
/*********************************************************************
|
||||
* Software License Agreement (AGPL-3 License)
|
||||
*
|
||||
* OpenViBE Designer
|
||||
* Based on OpenViBE V1.1.0, Copyright (C) Inria, 2006-2015
|
||||
* Copyright (C) Inria, 2015-2017,V1.0
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "mCBoxAlgorithmViz.hpp"
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace AdvancedVisualization {
|
||||
template <bool bHorizontalStack, bool bDrawBorders, class TRendererFactoryClass, class TRulerClass>
|
||||
class TBoxAlgorithmStackedContinuousViz : public CBoxAlgorithmViz
|
||||
{
|
||||
public:
|
||||
|
||||
TBoxAlgorithmStackedContinuousViz(const CIdentifier& classID, const std::vector<int>& parameters);
|
||||
bool initialize() override;
|
||||
bool uninitialize() override;
|
||||
bool process() override;
|
||||
|
||||
_IsDerivedFromClass_Final_(CBoxAlgorithmViz, m_ClassID)
|
||||
|
||||
Toolkit::TStimulationDecoder<TBoxAlgorithmStackedContinuousViz<bHorizontalStack, bDrawBorders, TRendererFactoryClass, TRulerClass>> m_StimDecoder;
|
||||
Toolkit::TStreamedMatrixDecoder<TBoxAlgorithmStackedContinuousViz<bHorizontalStack, bDrawBorders, TRendererFactoryClass, TRulerClass>>
|
||||
m_MatrixDecoder;
|
||||
|
||||
TRendererFactoryClass m_RendererFactory;
|
||||
std::vector<IRenderer*> m_Renderers;
|
||||
|
||||
protected:
|
||||
|
||||
void draw() override;
|
||||
};
|
||||
|
||||
class CBoxAlgorithmStackedContinuousVizListener final : public CBoxAlgorithmVizListener
|
||||
{
|
||||
public:
|
||||
|
||||
explicit CBoxAlgorithmStackedContinuousVizListener(const std::vector<int>& parameters) : CBoxAlgorithmVizListener(parameters) { }
|
||||
|
||||
bool onInputTypeChanged(Kernel::IBox& box, const size_t index) override
|
||||
{
|
||||
CIdentifier typeID = CIdentifier::undefined();
|
||||
box.getInputType(index, typeID);
|
||||
if (!this->getTypeManager().isDerivedFromStream(typeID, OV_TypeId_StreamedMatrix)) { box.setInputType(index, OV_TypeId_StreamedMatrix); }
|
||||
box.setInputType(1, OV_TypeId_Stimulations);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
template <bool bHorizontalStack, bool bDrawBorders, class TRendererFactoryClass, class TRulerClass = IRuler>
|
||||
class TBoxAlgorithmStackedContinuousVizDesc : public CBoxAlgorithmVizDesc
|
||||
{
|
||||
public:
|
||||
|
||||
TBoxAlgorithmStackedContinuousVizDesc(const CString& name, const CIdentifier& descClassID,
|
||||
const CIdentifier& classID, const CString& addedSoftwareVersion,
|
||||
const CString& updatedSoftwareVersion, const CParameterSet& parameterSet,
|
||||
const CString& shortDesc, const CString& detailedDesc)
|
||||
: CBoxAlgorithmVizDesc(name, descClassID, classID, addedSoftwareVersion, updatedSoftwareVersion, parameterSet, shortDesc, detailedDesc) { }
|
||||
|
||||
Plugins::IPluginObject* create() override
|
||||
{
|
||||
return new TBoxAlgorithmStackedContinuousViz<bHorizontalStack, bDrawBorders, TRendererFactoryClass, TRulerClass>(m_ClassID, m_Parameters);
|
||||
}
|
||||
|
||||
Plugins::IBoxListener* createBoxListener() const override { return new CBoxAlgorithmStackedContinuousVizListener(m_Parameters); }
|
||||
|
||||
CString getCategory() const override { return CString("Advanced Visualization/") + m_CategoryName; }
|
||||
|
||||
_IsDerivedFromClass_Final_(OpenViBE::Plugins::IBoxAlgorithmDesc, m_DescClassID)
|
||||
};
|
||||
|
||||
|
||||
template <bool bHorizontalStack, bool bDrawBorders, class TRendererFactoryClass, class TRulerClass>
|
||||
TBoxAlgorithmStackedContinuousViz<bHorizontalStack, bDrawBorders, TRendererFactoryClass, TRulerClass>::TBoxAlgorithmStackedContinuousViz(
|
||||
const CIdentifier& classID, const std::vector<int>& parameters) : CBoxAlgorithmViz(classID, parameters) { }
|
||||
|
||||
template <bool bHorizontalStack, bool bDrawBorders, class TRendererFactoryClass, class TRulerClass>
|
||||
bool TBoxAlgorithmStackedContinuousViz<bHorizontalStack, bDrawBorders, TRendererFactoryClass, TRulerClass>::initialize()
|
||||
|
||||
{
|
||||
const bool res = CBoxAlgorithmViz::initialize();
|
||||
|
||||
m_MatrixDecoder.initialize(*this, 0);
|
||||
m_StimDecoder.initialize(*this, 1);
|
||||
|
||||
m_RendererCtx->clear();
|
||||
m_RendererCtx->setTranslucency(float(m_Translucency));
|
||||
// m_rendererCtx->setTranslucency(m_nFlowerRing);
|
||||
m_RendererCtx->scaleBy(float(m_DataScale));
|
||||
m_RendererCtx->setPositiveOnly(m_IsPositive);
|
||||
m_RendererCtx->setAxisDisplay(m_ShowAxis);
|
||||
m_RendererCtx->setParentRendererContext(&getContext());
|
||||
|
||||
m_SubRendererCtx->clear();
|
||||
m_SubRendererCtx->setParentRendererContext(m_RendererCtx);
|
||||
|
||||
m_Ruler = new TRulerClass;
|
||||
m_Ruler->setRendererContext(m_RendererCtx);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
template <bool bHorizontalStack, bool bDrawBorders, class TRendererFactoryClass, class TRulerClass>
|
||||
bool TBoxAlgorithmStackedContinuousViz<bHorizontalStack, bDrawBorders, TRendererFactoryClass, TRulerClass>::uninitialize()
|
||||
|
||||
{
|
||||
for (size_t i = 0; i < m_Renderers.size(); ++i) { m_RendererFactory.release(m_Renderers[i]); }
|
||||
m_Renderers.clear();
|
||||
|
||||
delete m_SubRendererCtx;
|
||||
m_SubRendererCtx = nullptr;
|
||||
|
||||
delete m_RendererCtx;
|
||||
m_RendererCtx = nullptr;
|
||||
|
||||
delete m_Ruler;
|
||||
m_Ruler = nullptr;
|
||||
|
||||
m_StimDecoder.uninitialize();
|
||||
m_MatrixDecoder.uninitialize();
|
||||
|
||||
return CBoxAlgorithmViz::uninitialize();
|
||||
}
|
||||
|
||||
template <bool bHorizontalStack, bool bDrawBorders, class TRendererFactoryClass, class TRulerClass>
|
||||
bool TBoxAlgorithmStackedContinuousViz<bHorizontalStack, bDrawBorders, TRendererFactoryClass, TRulerClass>::process()
|
||||
{
|
||||
Kernel::IBoxIO& boxContext = this->getDynamicBoxContext();
|
||||
const size_t nInput = this->getStaticBoxContext().getInputCount();
|
||||
size_t i, j;
|
||||
|
||||
for (i = 0; i < boxContext.getInputChunkCount(0); ++i)
|
||||
{
|
||||
m_MatrixDecoder.decode(size_t(i));
|
||||
|
||||
CMatrix* matrix = m_MatrixDecoder.getOutputMatrix();
|
||||
size_t nChannel = matrix->getDimensionSize(0);
|
||||
size_t nSample = matrix->getDimensionSize(1);
|
||||
|
||||
if (nChannel == 0)
|
||||
{
|
||||
this->getLogManager() << Kernel::LogLevel_Error << "Input stream " << i << " has 0 channels\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (matrix->getDimensionCount() == 1)
|
||||
{
|
||||
nChannel = matrix->getDimensionSize(0);
|
||||
nSample = 1;
|
||||
}
|
||||
|
||||
if (m_MatrixDecoder.isHeaderReceived())
|
||||
{
|
||||
GtkTreeIter gtkTreeIter;
|
||||
gtk_list_store_clear(m_ChannelListStore);
|
||||
|
||||
m_Swaps.resize(nSample);
|
||||
|
||||
for (j = 0; j < m_Renderers.size(); ++j) { m_RendererFactory.release(m_Renderers[j]); }
|
||||
m_Renderers.clear();
|
||||
m_Renderers.resize(nChannel);
|
||||
|
||||
m_SubRendererCtx->clear();
|
||||
m_SubRendererCtx->setParentRendererContext(m_RendererCtx);
|
||||
m_SubRendererCtx->setTimeLocked(m_IsTimeLocked);
|
||||
m_SubRendererCtx->setStackCount(nChannel);
|
||||
for (j = 0; j < nSample; ++j)
|
||||
{
|
||||
std::string name = trim(matrix->getDimensionLabel(1, size_t(j)));
|
||||
std::string subname = name;
|
||||
std::transform(name.begin(), name.end(), subname.begin(), tolower);
|
||||
const CVertex v = m_ChannelPositions[subname];
|
||||
m_SubRendererCtx->addChannel(name, v.x, v.y, v.z);
|
||||
}
|
||||
|
||||
m_RendererCtx->clear();
|
||||
m_RendererCtx->setTranslucency(float(m_Translucency));
|
||||
m_RendererCtx->setTimeScale(m_TimeScale);
|
||||
m_RendererCtx->setElementCount(m_NElement);
|
||||
m_RendererCtx->scaleBy(float(m_DataScale));
|
||||
m_RendererCtx->setParentRendererContext(&getContext());
|
||||
m_RendererCtx->setTimeLocked(m_IsTimeLocked);
|
||||
m_RendererCtx->setXYZPlotDepth(m_XYZPlotHasDepth);
|
||||
|
||||
gtk_tree_view_set_model(m_ChannelTreeView, nullptr);
|
||||
for (j = 0; j < nChannel; ++j)
|
||||
{
|
||||
std::string name = trim(matrix->getDimensionLabel(0, size_t(j)));
|
||||
std::string subname = name;
|
||||
std::transform(name.begin(), name.end(), subname.begin(), tolower);
|
||||
const CVertex v = m_ChannelPositions[subname];
|
||||
|
||||
if (name.empty()) { name = "Channel " + std::to_string(j + 1); }
|
||||
|
||||
m_Renderers[j] = m_RendererFactory.create();
|
||||
m_Renderers[j]->setChannelCount(nSample);
|
||||
m_Renderers[j]->setSampleCount(size_t(m_NElement)); // $$$
|
||||
// m_Renderers[j]->setSampleCount(size_t(m_TimeScaleW)); // $$$
|
||||
|
||||
m_RendererCtx->addChannel(name, v.x, v.y, v.z);
|
||||
// m_rendererCtx->addChannel(sanitize(matrix->getDimensionLabel(0, j)));
|
||||
gtk_list_store_append(m_ChannelListStore, >kTreeIter);
|
||||
gtk_list_store_set(m_ChannelListStore, >kTreeIter, 0, j + 1, 1, name.c_str(), -1);
|
||||
}
|
||||
gtk_tree_view_set_model(m_ChannelTreeView, GTK_TREE_MODEL(m_ChannelListStore));
|
||||
gtk_tree_selection_select_all(gtk_tree_view_get_selection(m_ChannelTreeView));
|
||||
|
||||
if (m_TypeID == OV_TypeId_Signal)
|
||||
{
|
||||
m_RendererCtx->setDataType(CRendererContext::EDataType::Signal);
|
||||
m_SubRendererCtx->setDataType(CRendererContext::EDataType::Signal);
|
||||
}
|
||||
else if (m_TypeID == OV_TypeId_Spectrum)
|
||||
{
|
||||
m_RendererCtx->setDataType(CRendererContext::EDataType::Spectrum);
|
||||
m_SubRendererCtx->setDataType(CRendererContext::EDataType::Spectrum);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_RendererCtx->setDataType(CRendererContext::EDataType::Matrix);
|
||||
m_SubRendererCtx->setDataType(CRendererContext::EDataType::Matrix);
|
||||
}
|
||||
|
||||
m_Ruler->setRenderer(nChannel ? m_Renderers[0] : nullptr);
|
||||
|
||||
m_RebuildNeeded = true;
|
||||
m_RefreshNeeded = true;
|
||||
m_RedrawNeeded = true;
|
||||
}
|
||||
if (m_MatrixDecoder.isBufferReceived())
|
||||
{
|
||||
m_Time1 = m_Time2;
|
||||
m_Time2 = boxContext.getInputChunkEndTime(0, size_t(i));
|
||||
const uint64_t interChunkDuration = m_Time2 - m_Time1;
|
||||
const uint64_t chunkDuration = (boxContext.getInputChunkEndTime(0, size_t(i)) - boxContext.getInputChunkStartTime(0, size_t(i)));
|
||||
const uint64_t sampleDuration = chunkDuration / m_NElement;
|
||||
if (m_RendererCtx->isTimeLocked())
|
||||
{
|
||||
if ((interChunkDuration & ~0xf) != (m_RendererCtx->getSampleDuration() & ~0xf) && interChunkDuration != 0
|
||||
) // 0xf mask avoids rounding errors
|
||||
{
|
||||
m_SubRendererCtx->setSampleDuration(interChunkDuration);
|
||||
m_RendererCtx->setSampleDuration(interChunkDuration);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_SubRendererCtx->setSampleDuration(sampleDuration);
|
||||
m_RendererCtx->setSampleDuration(sampleDuration);
|
||||
}
|
||||
|
||||
m_RendererCtx->setSpectrumFrequencyRange(size_t((uint64_t(nSample) << 32) / chunkDuration));
|
||||
m_RendererCtx->setMinimumSpectrumFrequency(size_t(gtk_spin_button_get_value(GTK_SPIN_BUTTON(m_FrequencyBandMin))));
|
||||
m_RendererCtx->setMaximumSpectrumFrequency(size_t(gtk_spin_button_get_value(GTK_SPIN_BUTTON(m_FrequencyBandMax))));
|
||||
|
||||
for (j = 0; j < nChannel; ++j)
|
||||
{
|
||||
// Feed renderer with actual samples
|
||||
for (size_t k = 0; k < nSample; ++k) { m_Swaps[nSample - k - 1] = float(matrix->getBuffer()[j * nSample + k]); }
|
||||
m_Renderers[j]->feed(&m_Swaps[0]);
|
||||
|
||||
// Adjust feeding depending on theoretical dates
|
||||
if (m_RendererCtx->isTimeLocked() && m_RendererCtx->getSampleDuration())
|
||||
{
|
||||
const auto nTheoreticalSample = size_t(m_Time2 / m_RendererCtx->getSampleDuration());
|
||||
if (nTheoreticalSample > m_Renderers[j]->getHistoryCount())
|
||||
{
|
||||
m_Renderers[j]->prefeed(nTheoreticalSample - m_Renderers[j]->getHistoryCount());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_RefreshNeeded = true;
|
||||
m_RedrawNeeded = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (nInput > 1)
|
||||
{
|
||||
for (i = 0; i < boxContext.getInputChunkCount(1); ++i)
|
||||
{
|
||||
m_StimDecoder.decode(size_t(i));
|
||||
if (m_StimDecoder.isBufferReceived())
|
||||
{
|
||||
IStimulationSet* stimulationSet = m_StimDecoder.getOutputStimulationSet();
|
||||
for (j = 0; j < stimulationSet->getStimulationCount(); ++j)
|
||||
{
|
||||
m_Renderers[0]->feed(stimulationSet->getStimulationDate(j), stimulationSet->getStimulationIdentifier(j));
|
||||
m_RedrawNeeded = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
size_t rendererSampleCount = 0;
|
||||
if (m_RendererCtx->isTimeLocked())
|
||||
{
|
||||
if (0 != m_RendererCtx->getSampleDuration()) { rendererSampleCount = size_t(m_RendererCtx->getTimeScale() / m_RendererCtx->getSampleDuration()); }
|
||||
}
|
||||
else { rendererSampleCount = size_t(m_RendererCtx->getElementCount()); }
|
||||
|
||||
if (rendererSampleCount != 0)
|
||||
{
|
||||
for (j = 0; j < m_Renderers.size(); ++j)
|
||||
{
|
||||
if (rendererSampleCount != m_Renderers[j]->getSampleCount())
|
||||
{
|
||||
m_Renderers[j]->setSampleCount(rendererSampleCount);
|
||||
m_RebuildNeeded = true;
|
||||
m_RefreshNeeded = true;
|
||||
m_RedrawNeeded = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (m_RebuildNeeded) { for (auto& renderer : m_Renderers) { renderer->rebuild(*m_SubRendererCtx); } }
|
||||
if (m_RefreshNeeded) { for (auto& renderer : m_Renderers) { renderer->refresh(*m_SubRendererCtx); } }
|
||||
if (m_RedrawNeeded) { this->redraw(); }
|
||||
|
||||
m_RebuildNeeded = false;
|
||||
m_RefreshNeeded = false;
|
||||
m_RedrawNeeded = false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <bool bHorizontalStack, bool bDrawBorders, class TRendererFactoryClass, class TRulerClass>
|
||||
void TBoxAlgorithmStackedContinuousViz<bHorizontalStack, bDrawBorders, TRendererFactoryClass, TRulerClass>::draw()
|
||||
|
||||
{
|
||||
CBoxAlgorithmViz::preDraw();
|
||||
|
||||
if (m_RendererCtx->getSelectedCount() != 0)
|
||||
{
|
||||
glPushMatrix();
|
||||
glScalef(1, 1.F / m_RendererCtx->getSelectedCount(), 1);
|
||||
for (size_t i = 0; i < m_RendererCtx->getSelectedCount(); ++i)
|
||||
{
|
||||
glPushAttrib(GL_ALL_ATTRIB_BITS);
|
||||
glPushMatrix();
|
||||
glColor4f(m_Color.r, m_Color.g, m_Color.b, m_RendererCtx->getTranslucency());
|
||||
glTranslatef(0, m_RendererCtx->getSelectedCount() - i - 1.F, 0);
|
||||
if (!bHorizontalStack)
|
||||
{
|
||||
glScalef(1, -1, 1);
|
||||
glRotatef(-90, 0, 0, 1);
|
||||
}
|
||||
m_SubRendererCtx->setAspect(m_RendererCtx->getAspect());
|
||||
m_SubRendererCtx->setStackCount(m_RendererCtx->getSelectedCount());
|
||||
m_SubRendererCtx->setStackIndex(i);
|
||||
m_Renderers[m_RendererCtx->getSelected(i)]->render(*m_SubRendererCtx);
|
||||
if (bDrawBorders)
|
||||
{
|
||||
glDisable(GL_TEXTURE_1D);
|
||||
glDisable(GL_BLEND);
|
||||
glColor3f(0, 0, 0);
|
||||
glBegin(GL_LINE_LOOP);
|
||||
glVertex2f(0, 0);
|
||||
glVertex2f(1, 0);
|
||||
glVertex2f(1, 1);
|
||||
glVertex2f(0, 1);
|
||||
glEnd();
|
||||
}
|
||||
glPopMatrix();
|
||||
glPopAttrib();
|
||||
}
|
||||
glPopMatrix();
|
||||
}
|
||||
|
||||
CBoxAlgorithmViz::postDraw();
|
||||
}
|
||||
} // namespace AdvancedVisualization
|
||||
} // namespace OpenViBE
|
||||
+375
@@ -0,0 +1,375 @@
|
||||
/*********************************************************************
|
||||
* Software License Agreement (AGPL-3 License)
|
||||
*
|
||||
* OpenViBE Designer
|
||||
* Based on OpenViBE V1.1.0, Copyright (C) Inria, 2006-2015
|
||||
* Copyright (C) Inria, 2015-2017,V1.0
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "mCBoxAlgorithmViz.hpp"
|
||||
|
||||
#if defined TARGET_OS_Windows
|
||||
#define snprintf _snprintf
|
||||
#endif
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace AdvancedVisualization {
|
||||
template <bool bDrawBorders, class TRendererFactoryClass, class TRulerClass>
|
||||
class TBoxAlgorithmStackedInstantViz : public CBoxAlgorithmViz
|
||||
{
|
||||
public:
|
||||
|
||||
TBoxAlgorithmStackedInstantViz(const CIdentifier& classId, const std::vector<int>& parameters);
|
||||
bool initialize() override;
|
||||
bool uninitialize() override;
|
||||
bool process() override;
|
||||
|
||||
_IsDerivedFromClass_Final_(CBoxAlgorithmViz, m_ClassID)
|
||||
|
||||
Toolkit::TStimulationDecoder<TBoxAlgorithmStackedInstantViz<bDrawBorders, TRendererFactoryClass, TRulerClass>> m_StimDecoder;
|
||||
Toolkit::TStreamedMatrixDecoder<TBoxAlgorithmStackedInstantViz<bDrawBorders, TRendererFactoryClass, TRulerClass>> m_MatrixDecoder;
|
||||
|
||||
TRendererFactoryClass m_RendererFactory;
|
||||
std::vector<IRenderer*> m_Renderers;
|
||||
|
||||
protected:
|
||||
|
||||
void draw() override;
|
||||
};
|
||||
|
||||
class CBoxAlgorithmStackedInstantVizListener final : public CBoxAlgorithmVizListener
|
||||
{
|
||||
public:
|
||||
|
||||
CBoxAlgorithmStackedInstantVizListener(const std::vector<int>& parameters) : CBoxAlgorithmVizListener(parameters) { }
|
||||
|
||||
bool onInputTypeChanged(Kernel::IBox& box, const size_t index) override
|
||||
{
|
||||
CIdentifier typeID = CIdentifier::undefined();
|
||||
box.getInputType(index, typeID);
|
||||
if (!this->getTypeManager().isDerivedFromStream(typeID, OV_TypeId_TimeFrequency)) { box.setInputType(index, OV_TypeId_TimeFrequency); }
|
||||
box.setInputType(1, OV_TypeId_Stimulations);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
template <bool bDrawBorders, class TRendererFactoryClass, class TRulerClass = IRuler>
|
||||
class TBoxAlgorithmStackedInstantVizDesc : public CBoxAlgorithmVizDesc
|
||||
{
|
||||
public:
|
||||
|
||||
TBoxAlgorithmStackedInstantVizDesc(const CString& name, const CIdentifier& descClassID, const CIdentifier& classID,
|
||||
const CString& addedSoftwareVersion, const CString& updatedSoftwareVersion,
|
||||
const CParameterSet& parameterSet, const CString& shortDesc, const CString& detailedDesc)
|
||||
: CBoxAlgorithmVizDesc(name, descClassID, classID, addedSoftwareVersion, updatedSoftwareVersion, parameterSet, shortDesc, detailedDesc) { }
|
||||
|
||||
Plugins::IPluginObject* create() override
|
||||
{
|
||||
return new TBoxAlgorithmStackedInstantViz<bDrawBorders, TRendererFactoryClass, TRulerClass>(m_ClassID, m_Parameters);
|
||||
}
|
||||
|
||||
Plugins::IBoxListener* createBoxListener() const override { return new CBoxAlgorithmStackedInstantVizListener(m_Parameters); }
|
||||
|
||||
CString getCategory() const override { return CString("Advanced Visualization/") + m_CategoryName; }
|
||||
|
||||
_IsDerivedFromClass_Final_(OpenViBE::Plugins::IBoxAlgorithmDesc, m_DescClassID)
|
||||
};
|
||||
|
||||
|
||||
template <bool bDrawBorders, class TRendererFactoryClass, class TRulerClass>
|
||||
TBoxAlgorithmStackedInstantViz<bDrawBorders, TRendererFactoryClass, TRulerClass>::TBoxAlgorithmStackedInstantViz(
|
||||
const CIdentifier& classId, const std::vector<int>& parameters)
|
||||
: CBoxAlgorithmViz(classId, parameters) { }
|
||||
|
||||
template <bool bDrawBorders, class TRendererFactoryClass, class TRulerClass>
|
||||
bool TBoxAlgorithmStackedInstantViz<bDrawBorders, TRendererFactoryClass, TRulerClass>::initialize()
|
||||
|
||||
{
|
||||
const bool res = CBoxAlgorithmViz::initialize();
|
||||
|
||||
m_MatrixDecoder.initialize(*this, 0);
|
||||
m_StimDecoder.initialize(*this, 1);
|
||||
|
||||
m_RendererCtx->clear();
|
||||
m_RendererCtx->setTranslucency(float(m_Translucency));
|
||||
m_RendererCtx->scaleBy(float(m_DataScale));
|
||||
m_RendererCtx->setPositiveOnly(true);
|
||||
m_RendererCtx->setAxisDisplay(m_ShowAxis);
|
||||
m_RendererCtx->setParentRendererContext(&getContext());
|
||||
|
||||
m_SubRendererCtx->clear();
|
||||
m_SubRendererCtx->setParentRendererContext(m_RendererCtx);
|
||||
|
||||
m_Ruler = new TRulerClass;
|
||||
m_Ruler->setRendererContext(m_RendererCtx);
|
||||
|
||||
CMatrix gradientMatrix;
|
||||
VisualizationToolkit::ColorGradient::parse(gradientMatrix, m_ColorGradient);
|
||||
for (size_t step = 0; step < gradientMatrix.getDimensionSize(1); ++step)
|
||||
{
|
||||
const double currentStepValue = gradientMatrix.getBuffer()[4 * step + 0];
|
||||
gradientMatrix.getBuffer()[4 * step + 0] = (currentStepValue / 100.0) * 50.0 + 50.0;
|
||||
}
|
||||
VisualizationToolkit::ColorGradient::format(m_ColorGradient, gradientMatrix);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
template <bool TDrawBorders, class TRendererFactoryClass, class TRulerClass>
|
||||
bool TBoxAlgorithmStackedInstantViz<TDrawBorders, TRendererFactoryClass, TRulerClass>::uninitialize()
|
||||
|
||||
{
|
||||
for (size_t i = 0; i < m_Renderers.size(); ++i) { m_RendererFactory.release(m_Renderers[i]); }
|
||||
m_Renderers.clear();
|
||||
|
||||
delete m_SubRendererCtx;
|
||||
m_SubRendererCtx = nullptr;
|
||||
|
||||
delete m_RendererCtx;
|
||||
m_RendererCtx = nullptr;
|
||||
|
||||
delete m_Ruler;
|
||||
m_Ruler = nullptr;
|
||||
|
||||
m_StimDecoder.uninitialize();
|
||||
m_MatrixDecoder.uninitialize();
|
||||
|
||||
return CBoxAlgorithmViz::uninitialize();
|
||||
}
|
||||
|
||||
template <bool TDrawBorders, class TRendererFactoryClass, class TRulerClass>
|
||||
bool TBoxAlgorithmStackedInstantViz<TDrawBorders, TRendererFactoryClass, TRulerClass>::process()
|
||||
|
||||
{
|
||||
const Kernel::IBox& staticBoxContext = this->getStaticBoxContext();
|
||||
Kernel::IBoxIO& dynamicBoxContext = this->getDynamicBoxContext();
|
||||
|
||||
for (size_t chunk = 0; chunk < dynamicBoxContext.getInputChunkCount(0); ++chunk)
|
||||
{
|
||||
m_MatrixDecoder.decode(chunk);
|
||||
|
||||
CMatrix* inputMatrix = m_MatrixDecoder.getOutputMatrix();
|
||||
const size_t nChannel = inputMatrix->getDimensionSize(0);
|
||||
|
||||
if (nChannel == 0)
|
||||
{
|
||||
this->getLogManager() << Kernel::LogLevel_Error << "Input stream " << chunk << " has 0 channels\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_MatrixDecoder.isHeaderReceived())
|
||||
{
|
||||
for (auto renderer : m_Renderers) { m_RendererFactory.release(renderer); }
|
||||
m_Renderers.clear();
|
||||
m_Renderers.resize(nChannel);
|
||||
|
||||
m_SubRendererCtx->clear();
|
||||
m_SubRendererCtx->setParentRendererContext(m_RendererCtx);
|
||||
m_SubRendererCtx->setTimeLocked(false);
|
||||
m_SubRendererCtx->setStackCount(nChannel);
|
||||
m_SubRendererCtx->setPositiveOnly(true);
|
||||
|
||||
|
||||
m_RendererCtx->clear();
|
||||
m_RendererCtx->setTranslucency(float(m_Translucency));
|
||||
m_RendererCtx->setTimeScale(1);
|
||||
m_RendererCtx->scaleBy(float(m_DataScale));
|
||||
m_RendererCtx->setParentRendererContext(&getContext());
|
||||
m_RendererCtx->setTimeLocked(false);
|
||||
m_RendererCtx->setXYZPlotDepth(false);
|
||||
m_RendererCtx->setPositiveOnly(true);
|
||||
|
||||
if (m_TypeID == OV_TypeId_TimeFrequency)
|
||||
{
|
||||
GtkTreeIter gtkTreeIter;
|
||||
gtk_list_store_clear(m_ChannelListStore);
|
||||
|
||||
const size_t frequencyCount = inputMatrix->getDimensionSize(1);
|
||||
const size_t nSample = inputMatrix->getDimensionSize(2);
|
||||
|
||||
// I do not know what this is for...
|
||||
for (size_t frequency = 0; frequency < frequencyCount; ++frequency)
|
||||
{
|
||||
try
|
||||
{
|
||||
const double frequencyValue = std::stod(inputMatrix->getDimensionLabel(1, frequency), nullptr);
|
||||
const int stringSize = snprintf(nullptr, 0, "%.2f", frequencyValue) + 1;
|
||||
if (stringSize > 0)
|
||||
{
|
||||
std::unique_ptr<char[]> buffer(new char[stringSize]);
|
||||
snprintf(buffer.get(), size_t(stringSize), "%.2f", frequencyValue);
|
||||
m_RendererCtx->setDimensionLabel(1, frequencyCount - frequency - 1, buffer.get());
|
||||
}
|
||||
}
|
||||
catch (...) { m_RendererCtx->setDimensionLabel(1, frequencyCount - frequency - 1, "NaN"); }
|
||||
m_SubRendererCtx->addChannel("", 0, 0, 0);
|
||||
}
|
||||
|
||||
|
||||
m_RendererCtx->setDataType(CRendererContext::EDataType::TimeFrequency);
|
||||
m_SubRendererCtx->setDataType(CRendererContext::EDataType::TimeFrequency);
|
||||
|
||||
m_RendererCtx->setElementCount(nSample);
|
||||
m_SubRendererCtx->setElementCount(nSample);
|
||||
gtk_tree_view_set_model(m_ChannelTreeView, nullptr);
|
||||
|
||||
for (size_t channel = 0; channel < nChannel; ++channel)
|
||||
{
|
||||
std::string channelName = trim(inputMatrix->getDimensionLabel(0, channel));
|
||||
std::string lowercaseChannelName = channelName;
|
||||
std::transform(channelName.begin(), channelName.end(), lowercaseChannelName.begin(), tolower);
|
||||
const CVertex v = m_ChannelPositions[lowercaseChannelName];
|
||||
|
||||
if (channelName.empty()) { channelName = "Channel " + std::to_string(channel + 1); }
|
||||
|
||||
m_Renderers[channel] = m_RendererFactory.create();
|
||||
|
||||
// The channels in the sub-renderer are the frequencies in the spectrum
|
||||
m_Renderers[channel]->setChannelCount(frequencyCount);
|
||||
m_Renderers[channel]->setSampleCount(nSample);
|
||||
|
||||
m_RendererCtx->addChannel(channelName, v.x, v.y, v.z);
|
||||
gtk_list_store_append(m_ChannelListStore, >kTreeIter);
|
||||
gtk_list_store_set(m_ChannelListStore, >kTreeIter, 0, channel + 1, 1, channelName.c_str(), -1);
|
||||
}
|
||||
gtk_tree_view_set_model(m_ChannelTreeView, GTK_TREE_MODEL(m_ChannelListStore));
|
||||
gtk_tree_selection_select_all(gtk_tree_view_get_selection(m_ChannelTreeView));
|
||||
}
|
||||
else
|
||||
{
|
||||
this->getLogManager() << Kernel::LogLevel_Error << "Input stream type is not supported\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
m_Ruler->setRenderer(nChannel ? m_Renderers[0] : nullptr);
|
||||
|
||||
m_RebuildNeeded = true;
|
||||
m_RefreshNeeded = true;
|
||||
m_RedrawNeeded = true;
|
||||
}
|
||||
|
||||
if (m_MatrixDecoder.isBufferReceived())
|
||||
{
|
||||
if (m_TypeID == OV_TypeId_TimeFrequency)
|
||||
{
|
||||
m_Time1 = m_Time2;
|
||||
m_Time2 = dynamicBoxContext.getInputChunkEndTime(0, chunk);
|
||||
|
||||
const size_t frequencyCount = inputMatrix->getDimensionSize(1);
|
||||
const size_t nSample = inputMatrix->getDimensionSize(2);
|
||||
|
||||
const uint64_t chunkDuration = dynamicBoxContext.getInputChunkEndTime(0, chunk) - dynamicBoxContext.getInputChunkStartTime(0, chunk);
|
||||
const uint64_t sampleDuration = chunkDuration / nSample;
|
||||
|
||||
m_SubRendererCtx->setSampleDuration(sampleDuration);
|
||||
m_RendererCtx->setSampleDuration(sampleDuration);
|
||||
|
||||
for (size_t channel = 0; channel < nChannel; ++channel)
|
||||
{
|
||||
// Feed renderer with actual samples
|
||||
for (size_t sample = 0; sample < nSample; ++sample)
|
||||
{
|
||||
m_Swaps.resize(frequencyCount);
|
||||
for (size_t frequency = 0; frequency < frequencyCount; ++frequency)
|
||||
{
|
||||
m_Swaps[frequencyCount - frequency - 1] = float(
|
||||
inputMatrix->getBuffer()[sample + frequency * nSample + channel * nSample * frequencyCount]);
|
||||
}
|
||||
m_Renderers[channel]->feed(&m_Swaps[0]);
|
||||
}
|
||||
}
|
||||
|
||||
m_RefreshNeeded = true;
|
||||
m_RedrawNeeded = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (staticBoxContext.getInputCount() > 1)
|
||||
{
|
||||
for (size_t i = 0; i < dynamicBoxContext.getInputChunkCount(1); ++i)
|
||||
{
|
||||
m_StimDecoder.decode(i);
|
||||
if (m_StimDecoder.isBufferReceived())
|
||||
{
|
||||
IStimulationSet* stimSet = m_StimDecoder.getOutputStimulationSet();
|
||||
for (size_t j = 0; j < stimSet->getStimulationCount(); ++j)
|
||||
{
|
||||
m_Renderers[0]->feed(stimSet->getStimulationDate(j), stimSet->getStimulationIdentifier(j));
|
||||
m_RedrawNeeded = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (m_RebuildNeeded) { for (auto& renderer : m_Renderers) { renderer->rebuild(*m_SubRendererCtx); } }
|
||||
if (m_RefreshNeeded) { for (auto& renderer : m_Renderers) { renderer->refresh(*m_SubRendererCtx); } }
|
||||
if (m_RedrawNeeded) { this->redraw(); }
|
||||
|
||||
m_RebuildNeeded = false;
|
||||
m_RefreshNeeded = false;
|
||||
m_RedrawNeeded = false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <bool bDrawBorders, class TRendererFactoryClass, class TRulerClass>
|
||||
void TBoxAlgorithmStackedInstantViz<bDrawBorders, TRendererFactoryClass, TRulerClass>::draw()
|
||||
|
||||
{
|
||||
CBoxAlgorithmViz::preDraw();
|
||||
|
||||
if (m_RendererCtx->getSelectedCount() != 0)
|
||||
{
|
||||
glPushMatrix();
|
||||
glScalef(1, 1.F / m_RendererCtx->getSelectedCount(), 1);
|
||||
for (size_t i = 0; i < m_RendererCtx->getSelectedCount(); ++i)
|
||||
{
|
||||
glPushAttrib(GL_ALL_ATTRIB_BITS);
|
||||
glPushMatrix();
|
||||
glColor4f(m_Color.r, m_Color.g, m_Color.b, m_RendererCtx->getTranslucency());
|
||||
glTranslatef(0, m_RendererCtx->getSelectedCount() - i - 1.F, 0);
|
||||
|
||||
m_SubRendererCtx->setAspect(m_RendererCtx->getAspect());
|
||||
m_SubRendererCtx->setStackCount(m_RendererCtx->getSelectedCount());
|
||||
m_SubRendererCtx->setStackIndex(i);
|
||||
m_Renderers[m_RendererCtx->getSelected(i)]->render(*m_SubRendererCtx);
|
||||
if (bDrawBorders)
|
||||
{
|
||||
glDisable(GL_TEXTURE_1D);
|
||||
glDisable(GL_BLEND);
|
||||
glColor3f(0, 0, 0);
|
||||
glBegin(GL_LINE_LOOP);
|
||||
glVertex2f(0, 0);
|
||||
glVertex2f(1, 0);
|
||||
glVertex2f(1, 1);
|
||||
glVertex2f(0, 1);
|
||||
glEnd();
|
||||
}
|
||||
glPopMatrix();
|
||||
glPopAttrib();
|
||||
}
|
||||
glPopMatrix();
|
||||
}
|
||||
|
||||
CBoxAlgorithmViz::postDraw();
|
||||
}
|
||||
} // namespace AdvancedVisualization
|
||||
} // namespace OpenViBE
|
||||
+354
@@ -0,0 +1,354 @@
|
||||
/*********************************************************************
|
||||
* Software License Agreement (AGPL-3 License)
|
||||
*
|
||||
* OpenViBE Designer
|
||||
* Based on OpenViBE V1.1.0, Copyright (C) Inria, 2006-2015
|
||||
* Copyright (C) Inria, 2015-2017,V1.0
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "m_defines.hpp"
|
||||
#include "m_VisualizationTools.hpp"
|
||||
#include "m_GtkGL.hpp"
|
||||
|
||||
#include <openvibe/ov_all.h>
|
||||
#include <visualization-toolkit/ovviz_all.h>
|
||||
|
||||
#if defined TARGET_OS_Windows
|
||||
#include <Windows.h>
|
||||
#endif
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include <GL/gl.h>
|
||||
#include <GL/glu.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
// #define __DIRECT_RENDER__
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace AdvancedVisualization {
|
||||
template <class TBox>
|
||||
class TGtkGLWidget
|
||||
{
|
||||
public:
|
||||
|
||||
TGtkGLWidget() : m_box(nullptr) { }
|
||||
|
||||
virtual ~TGtkGLWidget()
|
||||
{
|
||||
if (m_widget)
|
||||
{
|
||||
if (m_textureId)
|
||||
{
|
||||
GtkGL::preRender(m_widget);
|
||||
glDeleteTextures(1, &m_textureId);
|
||||
GtkGL::postRender(m_widget);
|
||||
}
|
||||
if (m_timeoutSrc) { g_source_destroy(m_timeoutSrc); }
|
||||
GtkGL::uninitialize(m_widget);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void initialize(TBox& box, GtkWidget* widget, GtkWidget* left, GtkWidget* right, GtkWidget* bottom)
|
||||
{
|
||||
GtkGL::initialize(widget);
|
||||
{
|
||||
m_box = &box;
|
||||
m_widget = widget;
|
||||
m_left = left;
|
||||
m_right = right;
|
||||
m_bottom = bottom;
|
||||
|
||||
::g_signal_connect(widget, "configure-event", G_CALLBACK(TGtkGLWidget<TBox>::configureCB), m_box);
|
||||
::g_signal_connect(widget, "expose-event", G_CALLBACK(TGtkGLWidget<TBox>::exposeCB), m_box);
|
||||
::g_signal_connect(widget, "button-press-event", G_CALLBACK(TGtkGLWidget<TBox>::mouseButtonCB), m_box);
|
||||
::g_signal_connect(widget, "button-release-event", G_CALLBACK(TGtkGLWidget<TBox>::mouseButtonCB), m_box);
|
||||
::g_signal_connect(widget, "motion-notify-event", G_CALLBACK(TGtkGLWidget<TBox>::motionNotifyCB), m_box);
|
||||
::g_signal_connect(widget, "enter-notify-event", G_CALLBACK(TGtkGLWidget<TBox>::enterNotifyCB), m_box);
|
||||
::g_signal_connect(gtk_widget_get_parent(widget), "key-press-event", G_CALLBACK(TGtkGLWidget<TBox>::keyPressCB), m_box);
|
||||
::g_signal_connect(gtk_widget_get_parent(widget), "key-release-event", G_CALLBACK(TGtkGLWidget<TBox>::keyReleaseCB), m_box);
|
||||
|
||||
::g_signal_connect_after(left, "expose-event", G_CALLBACK(TGtkGLWidget<TBox>::exposeLeftCB), m_box);
|
||||
::g_signal_connect_after(right, "expose-event", G_CALLBACK(TGtkGLWidget<TBox>::exposeRightCB), m_box);
|
||||
::g_signal_connect_after(bottom, "expose-event", G_CALLBACK(TGtkGLWidget<TBox>::exposeBottomCB), m_box);
|
||||
|
||||
m_timeoutSrc = g_timeout_source_new(250); // timeouts every 50 ms
|
||||
g_source_set_priority(m_timeoutSrc, G_PRIORITY_LOW);
|
||||
g_source_set_callback(m_timeoutSrc, GSourceFunc(timeoutRedrawCB), m_box, nullptr);
|
||||
g_source_attach(m_timeoutSrc, nullptr);
|
||||
|
||||
gtk_widget_queue_resize(widget);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void redrawTopLevelWindow(const bool immediate = false)
|
||||
{
|
||||
GtkWidget* top = gtk_widget_get_toplevel(m_widget);
|
||||
if (top != nullptr)
|
||||
{
|
||||
if (immediate)
|
||||
{
|
||||
gdk_window_process_updates(top->window, false);
|
||||
gtk_widget_queue_draw(top);
|
||||
}
|
||||
else { gdk_window_invalidate_rect(top->window, nullptr, true); }
|
||||
}
|
||||
}
|
||||
|
||||
virtual void redraw(const bool immediate = false)
|
||||
{
|
||||
if (immediate)
|
||||
{
|
||||
gdk_window_process_updates(m_widget->window, false);
|
||||
gtk_widget_queue_draw(m_widget);
|
||||
}
|
||||
else { gdk_window_invalidate_rect(m_widget->window, nullptr, true); }
|
||||
}
|
||||
|
||||
virtual void redrawLeft(const bool immediate = false)
|
||||
{
|
||||
if (immediate)
|
||||
{
|
||||
gdk_window_process_updates(m_left->window, false);
|
||||
gtk_widget_queue_draw(m_left);
|
||||
}
|
||||
else { gdk_window_invalidate_rect(m_left->window, nullptr, true); }
|
||||
}
|
||||
|
||||
virtual void redrawRight(const bool immediate = false)
|
||||
{
|
||||
if (immediate)
|
||||
{
|
||||
gdk_window_process_updates(m_right->window, false);
|
||||
gtk_widget_queue_draw(m_right);
|
||||
}
|
||||
else { gdk_window_invalidate_rect(m_right->window, nullptr, true); }
|
||||
}
|
||||
|
||||
virtual void redrawBottom(const bool immediate = false)
|
||||
{
|
||||
if (immediate)
|
||||
{
|
||||
gdk_window_process_updates(m_bottom->window, false);
|
||||
gtk_widget_queue_draw(m_bottom);
|
||||
}
|
||||
else { gdk_window_invalidate_rect(m_bottom->window, nullptr, true); }
|
||||
}
|
||||
|
||||
virtual void setPointSmoothingActive(const bool active = false)
|
||||
{
|
||||
if (active) { glEnable(GL_POINT_SMOOTH); }
|
||||
else { glDisable(GL_POINT_SMOOTH); }
|
||||
}
|
||||
|
||||
virtual uint32_t createTexture(const std::string& value)
|
||||
{
|
||||
#define M_GRADIENT_SIZE 128
|
||||
|
||||
if (m_textureId == 0)
|
||||
{
|
||||
const std::string str = (value.empty() ? "0:0,0,100; 25:0,100,100; 50:0,49,0; 75:100,100,0; 100:100,0,0" : value);
|
||||
|
||||
CMatrix gradientBase, gradient;
|
||||
VisualizationToolkit::ColorGradient::parse(gradientBase, str.c_str());
|
||||
VisualizationToolkit::ColorGradient::interpolate(gradient, gradientBase, M_GRADIENT_SIZE);
|
||||
|
||||
float texture[M_GRADIENT_SIZE][3];
|
||||
for (size_t i = 0; i < M_GRADIENT_SIZE; ++i)
|
||||
{
|
||||
texture[i][0] = float(gradient[i * 4 + 1] * .01);
|
||||
texture[i][1] = float(gradient[i * 4 + 2] * .01);
|
||||
texture[i][2] = float(gradient[i * 4 + 3] * .01);
|
||||
}
|
||||
|
||||
glGenTextures(1, &m_textureId);
|
||||
glBindTexture(GL_TEXTURE_1D, m_textureId);
|
||||
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); // GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); // LINEAR_MIPMAP_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP);
|
||||
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_T, GL_CLAMP);
|
||||
//glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
|
||||
//glTexImage1D(GL_TEXTURE_1D, 0, GL_RGB, __SIZE__, 0, GL_RGB, GL_UNSIGNED_BYTE, texture);
|
||||
gluBuild1DMipmaps(GL_TEXTURE_1D, GL_RGB, M_GRADIENT_SIZE, GL_RGB, GL_FLOAT, texture);
|
||||
}
|
||||
|
||||
#undef M_GRADIENT_SIZE
|
||||
|
||||
return m_textureId;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
GtkWidget* m_widget = nullptr;
|
||||
GtkWidget* m_left = nullptr;
|
||||
GtkWidget* m_right = nullptr;
|
||||
GtkWidget* m_bottom = nullptr;
|
||||
GSource* m_timeoutSrc = nullptr;
|
||||
|
||||
TBox* m_box = nullptr;
|
||||
|
||||
uint32_t m_textureId = 0;
|
||||
|
||||
private:
|
||||
|
||||
|
||||
static gboolean timeoutRedrawCB(TBox* box)
|
||||
{
|
||||
box->redraw();
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean configureCB(GtkWidget* widget, GdkEventConfigure* /*event*/, TBox* box)
|
||||
{
|
||||
GtkGL::preRender(widget);
|
||||
glViewport(0, 0, widget->allocation.width, widget->allocation.height);
|
||||
box->reshape(widget->allocation.width, widget->allocation.height);
|
||||
GtkGL::postRender(widget);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean exposeCB(GtkWidget* widget, GdkEventExpose* /*event*/, TBox* box)
|
||||
{
|
||||
const float d = 1.F;
|
||||
const float dx = d / (widget->allocation.width - d);
|
||||
const float dy = d / (widget->allocation.height - d);
|
||||
|
||||
GtkGL::preRender(widget);
|
||||
|
||||
glMatrixMode(GL_TEXTURE);
|
||||
glLoadIdentity();
|
||||
glTranslatef(0.5, 0, 0);
|
||||
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
gluOrtho2D(0 - dx, 1 + dx, 0 - dy, 1 + dy);
|
||||
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadIdentity();
|
||||
|
||||
glEnable(GL_POLYGON_OFFSET_FILL);
|
||||
glPolygonOffset(1.0, 1.0);
|
||||
|
||||
glEnable(GL_LINE_SMOOTH);
|
||||
glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
|
||||
glLineWidth(1);
|
||||
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
|
||||
|
||||
glEnable(GL_TEXTURE_1D);
|
||||
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glClearDepth(100);
|
||||
glClearColor(0, 0, 0, 0);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
glColor3f(1, 1, 1);
|
||||
|
||||
// Lighting
|
||||
const float fAmbient = 0.0F;
|
||||
const float fDiffuse = 1.0F;
|
||||
const float fSpecular = 1.0F;
|
||||
GLfloat ambient[] = { fAmbient, fAmbient, fAmbient, 1 };
|
||||
GLfloat diffuse[] = { fDiffuse, fDiffuse, fDiffuse, 1 };
|
||||
GLfloat specular[] = { fSpecular, fSpecular, fSpecular, 1 };
|
||||
GLfloat position0[] = { 3, 1, 2, 1 };
|
||||
GLfloat position1[] = { -3, 0, -2, 1 };
|
||||
glLightfv(GL_LIGHT0, GL_AMBIENT, ambient);
|
||||
glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse);
|
||||
glLightfv(GL_LIGHT0, GL_SPECULAR, specular);
|
||||
glLightfv(GL_LIGHT0, GL_POSITION, position0);
|
||||
glLightfv(GL_LIGHT1, GL_AMBIENT, ambient);
|
||||
glLightfv(GL_LIGHT1, GL_DIFFUSE, diffuse);
|
||||
glLightfv(GL_LIGHT1, GL_SPECULAR, specular);
|
||||
glLightfv(GL_LIGHT1, GL_POSITION, position1);
|
||||
glShadeModel(GL_SMOOTH);
|
||||
glEnable(GL_LIGHT0);
|
||||
glEnable(GL_LIGHT1);
|
||||
glEnable(GL_COLOR_MATERIAL);
|
||||
glDisable(GL_LIGHTING);
|
||||
|
||||
box->draw();
|
||||
|
||||
GtkGL::postRender(widget);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean enterNotifyCB(GtkWidget* /*widget*/, GdkEventCrossing* /*event*/, TBox* box)
|
||||
{
|
||||
box->redraw();
|
||||
//box->request();
|
||||
//box->m_redrawNeeded = true;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean exposeLeftCB(GtkWidget* /*widget*/, GdkEventExpose* /*event*/, TBox* box)
|
||||
{
|
||||
box->drawLeft();
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean exposeRightCB(GtkWidget* /*widget*/, GdkEventExpose* /*event*/, TBox* box)
|
||||
{
|
||||
box->drawRight();
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean exposeBottomCB(GtkWidget* /*widget*/, GdkEventExpose* /*event*/, TBox* box)
|
||||
{
|
||||
box->drawBottom();
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean mouseButtonCB(GtkWidget* /*widget*/, GdkEventButton* event, TBox* box)
|
||||
{
|
||||
int status = 0;
|
||||
switch (event->type)
|
||||
{
|
||||
case GDK_BUTTON_PRESS: status = 1;
|
||||
break;
|
||||
case GDK_2BUTTON_PRESS: status = 2;
|
||||
break;
|
||||
case GDK_3BUTTON_PRESS: status = 3;
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
box->mouseButton(int(event->x), int(event->y), event->button, status);
|
||||
box->draw();
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean motionNotifyCB(GtkWidget* /*widget*/, GdkEventMotion* event, TBox* box)
|
||||
{
|
||||
box->mouseMotion(int(event->x), int(event->y));
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean keyPressCB(GtkWidget* /*widget*/, GdkEventKey* event, TBox* box)
|
||||
{
|
||||
box->keyboard(0, 0, /*event->x, event->y,*/ event->keyval, true);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean keyReleaseCB(GtkWidget* /*widget*/, GdkEventKey* event, TBox* box)
|
||||
{
|
||||
box->keyboard(0, 0, /*event->x, event->y,*/ event->keyval, false);
|
||||
return TRUE;
|
||||
}
|
||||
};
|
||||
} // namespace AdvancedVisualization
|
||||
} // namespace OpenViBE
|
||||
+311
@@ -0,0 +1,311 @@
|
||||
/*********************************************************************
|
||||
* Software License Agreement (AGPL-3 License)
|
||||
*
|
||||
* OpenViBE Designer
|
||||
* Based on OpenViBE V1.1.0, Copyright (C) Inria, 2006-2015
|
||||
* Copyright (C) Inria, 2015-2017,V1.0
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "m_GtkGL.hpp"
|
||||
#include "m_defines.hpp"
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include <gdk/gdk.h>
|
||||
#if defined TARGET_OS_Windows
|
||||
#include <windows.h>
|
||||
#include <gdk/gdkwin32.h>
|
||||
#elif defined TARGET_OS_Linux || defined TARGET_OS_MacOS
|
||||
#include <gdk/gdkx.h>
|
||||
#include <GL/glx.h>
|
||||
#else
|
||||
#error unsupported platform
|
||||
#endif
|
||||
|
||||
// ###########################################################################################################################################################
|
||||
// ###########################################################################################################################################################
|
||||
//
|
||||
// GtkGL implementation
|
||||
//
|
||||
// ###########################################################################################################################################################
|
||||
// ###########################################################################################################################################################
|
||||
|
||||
#define GTK_GL_RENDERING_CONTEXT_NAME "GL Rendering Context"
|
||||
#define GTK_GL_DEVICE_CONTEXT_NAME "Device Context"
|
||||
#define GTK_GL_DEBUG(s) // g_debug("GtkGL : "#s);
|
||||
#define GTK_GL_WARNING(s) g_warning("GtkGL : "#s);
|
||||
|
||||
#if defined TARGET_OS_Windows
|
||||
|
||||
namespace {
|
||||
typedef bool (*gl_swap_interval_ext_t)(int);
|
||||
gl_swap_interval_ext_t wglSwapIntervalEXT = nullptr;
|
||||
} // namespace
|
||||
|
||||
#elif defined TARGET_OS_Linux || defined TARGET_OS_MacOS
|
||||
|
||||
namespace
|
||||
{
|
||||
typedef void (*glXSwapIntervalEXT_t)(Display*, GLXDrawable, int);
|
||||
glXSwapIntervalEXT_t glXSwapIntervalEXT = nullptr;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// ## WINDOWS ##############################################################################################################################################
|
||||
|
||||
#if defined TARGET_OS_Windows
|
||||
|
||||
namespace {
|
||||
void on_realize_cb(GtkWidget* widget, void* /*data*/)
|
||||
{
|
||||
GTK_GL_DEBUG("realize-callback");
|
||||
|
||||
gdk_window_ensure_native(gtk_widget_get_window(widget));
|
||||
|
||||
const HWND window = HWND(GDK_WINDOW_HWND(gtk_widget_get_window(widget)));
|
||||
const HDC drawingCtx = GetDC(window);
|
||||
|
||||
PIXELFORMATDESCRIPTOR pixelFormatDesc;
|
||||
pixelFormatDesc.nSize = sizeof(pixelFormatDesc);
|
||||
pixelFormatDesc.nVersion = 1;
|
||||
pixelFormatDesc.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
|
||||
pixelFormatDesc.iPixelType = PFD_TYPE_RGBA;
|
||||
pixelFormatDesc.cColorBits = 24;
|
||||
pixelFormatDesc.cAlphaBits = 8;
|
||||
pixelFormatDesc.cDepthBits = 32;
|
||||
pixelFormatDesc.iLayerType = PFD_MAIN_PLANE;
|
||||
|
||||
const int pixelFormatID = ChoosePixelFormat(drawingCtx, &pixelFormatDesc);
|
||||
|
||||
if (pixelFormatID == 0)
|
||||
{
|
||||
GTK_GL_WARNING("ChoosePixelFormat failed");
|
||||
GTK_GL_DEBUG("realize-callback::failed");
|
||||
return;
|
||||
}
|
||||
|
||||
if (SetPixelFormat(drawingCtx, pixelFormatID, &pixelFormatDesc) == 0)
|
||||
{
|
||||
GTK_GL_WARNING("SetPixelFormat failed");
|
||||
GTK_GL_DEBUG("realize-callback::failed");
|
||||
return;
|
||||
}
|
||||
|
||||
const HGLRC glRenderingCtx = wglCreateContext(drawingCtx);
|
||||
if (glRenderingCtx == nullptr)
|
||||
{
|
||||
GTK_GL_WARNING("wglCreateContext failed");
|
||||
GTK_GL_DEBUG("realize-callback::failed");
|
||||
return;
|
||||
}
|
||||
|
||||
g_object_set_data(G_OBJECT(widget), GTK_GL_RENDERING_CONTEXT_NAME, glRenderingCtx);
|
||||
g_object_set_data(G_OBJECT(widget), GTK_GL_DEVICE_CONTEXT_NAME, drawingCtx);
|
||||
|
||||
gtk_widget_queue_resize(widget);
|
||||
gtk_widget_set_double_buffered(widget, FALSE);
|
||||
|
||||
wglSwapIntervalEXT = gl_swap_interval_ext_t(wglGetProcAddress("wglSwapIntervalEXT"));
|
||||
|
||||
GTK_GL_DEBUG("realize-callback::success");
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void OpenViBE::AdvancedVisualization::GtkGL::initialize(GtkWidget* widget)
|
||||
{
|
||||
GTK_GL_DEBUG("initialize");
|
||||
g_signal_connect(widget, "realize", G_CALLBACK(on_realize_cb), nullptr);
|
||||
GTK_GL_DEBUG("initialize::success");
|
||||
}
|
||||
|
||||
void OpenViBE::AdvancedVisualization::GtkGL::uninitialize(GtkWidget* widget)
|
||||
{
|
||||
GTK_GL_DEBUG("uninitialize");
|
||||
|
||||
const HWND window = HWND(GDK_WINDOW_HWND(gtk_widget_get_window(widget)));
|
||||
|
||||
const auto glRenderingCtx = HGLRC(g_object_get_data(G_OBJECT(widget), GTK_GL_RENDERING_CONTEXT_NAME));
|
||||
wglDeleteContext(glRenderingCtx);
|
||||
|
||||
const HDC drawingCtx = HDC(g_object_get_data(G_OBJECT(widget), GTK_GL_DEVICE_CONTEXT_NAME));
|
||||
ReleaseDC(window, drawingCtx);
|
||||
|
||||
GTK_GL_DEBUG("uninitialize::success");
|
||||
}
|
||||
|
||||
void OpenViBE::AdvancedVisualization::GtkGL::preRender(GtkWidget* widget, const bool verticalSync)
|
||||
{
|
||||
GTK_GL_DEBUG("pre-render");
|
||||
|
||||
const HDC drawingCtx = HDC(g_object_get_data(G_OBJECT(widget), GTK_GL_DEVICE_CONTEXT_NAME));
|
||||
const auto glRenderingCtx = HGLRC(g_object_get_data(G_OBJECT(widget), GTK_GL_RENDERING_CONTEXT_NAME));
|
||||
|
||||
if (glRenderingCtx == nullptr)
|
||||
{
|
||||
GTK_GL_DEBUG("Rendering context not ready");
|
||||
GTK_GL_DEBUG("pre-render::failed");
|
||||
return;
|
||||
}
|
||||
|
||||
if (wglMakeCurrent(drawingCtx, glRenderingCtx) == 0)
|
||||
{
|
||||
GTK_GL_WARNING("wglMakeCurrent failed");
|
||||
GTK_GL_DEBUG("pre-render::failed");
|
||||
return;
|
||||
}
|
||||
|
||||
// Enable / Disable vsync
|
||||
if (wglSwapIntervalEXT != nullptr) { wglSwapIntervalEXT(verticalSync ? 1 : 0); }
|
||||
|
||||
GTK_GL_DEBUG("pre-render::success");
|
||||
}
|
||||
|
||||
void OpenViBE::AdvancedVisualization::GtkGL::postRender(GtkWidget* widget)
|
||||
{
|
||||
GTK_GL_DEBUG("post-render");
|
||||
|
||||
const HDC drawingCtx = HDC(g_object_get_data(G_OBJECT(widget), GTK_GL_DEVICE_CONTEXT_NAME));
|
||||
|
||||
if (drawingCtx == nullptr)
|
||||
{
|
||||
GTK_GL_DEBUG("Rendering context not ready");
|
||||
GTK_GL_DEBUG("post-render::failed");
|
||||
}
|
||||
else if (SwapBuffers(drawingCtx) == 0)
|
||||
{
|
||||
GTK_GL_WARNING("SwapBuffers failed");
|
||||
GTK_GL_DEBUG("post-render::failed");
|
||||
}
|
||||
else if (wglMakeCurrent(drawingCtx, nullptr) == 0)
|
||||
{
|
||||
GTK_GL_WARNING("wglMakeCurrent failed");
|
||||
GTK_GL_DEBUG("post-render::failed");
|
||||
}
|
||||
else { GTK_GL_DEBUG("post-render::success"); }
|
||||
}
|
||||
|
||||
// ## WINDOWS ##############################################################################################################################################
|
||||
|
||||
#elif defined TARGET_OS_Linux || defined TARGET_OS_MacOS
|
||||
|
||||
// ## LINUX ################################################################################################################################################
|
||||
|
||||
void OpenViBE::AdvancedVisualization::GtkGL::initialize(GtkWidget * widget)
|
||||
{
|
||||
GTK_GL_DEBUG("initialize");
|
||||
|
||||
// ::gdk_window_ensure_native(gtk_widget_get_window(widget));
|
||||
|
||||
::GdkScreen* screen = ::gdk_screen_get_default();
|
||||
::Display* display = GDK_SCREEN_XDISPLAY(screen);
|
||||
::gint screenNumber = GDK_SCREEN_XNUMBER(screen);
|
||||
|
||||
int visualInfoAttributes[] =
|
||||
{
|
||||
GLX_RGBA,
|
||||
GLX_RED_SIZE, 1,
|
||||
GLX_GREEN_SIZE, 1,
|
||||
GLX_BLUE_SIZE, 1,
|
||||
GLX_ALPHA_SIZE, 1,
|
||||
GLX_DOUBLEBUFFER,
|
||||
GLX_DEPTH_SIZE, 1,
|
||||
None
|
||||
};
|
||||
|
||||
if (!::glXQueryVersion(display, nullptr, nullptr))
|
||||
{
|
||||
GTK_GL_WARNING("initialize::failed");
|
||||
return;
|
||||
}
|
||||
|
||||
::XVisualInfo* visualInfo = ::glXChooseVisual(display, screenNumber, visualInfoAttributes);
|
||||
::GLXContext glRenderingCtx = glXCreateContext(display, visualInfo, nullptr, True);
|
||||
g_object_set_data(G_OBJECT(widget), GTK_GL_RENDERING_CONTEXT_NAME, glRenderingCtx);
|
||||
|
||||
#if 1
|
||||
/* Fix up colormap */
|
||||
::GdkVisual* visual = ::gdk_x11_screen_lookup_visual(screen, visualInfo->visualid);
|
||||
::GdkColormap* colorMap = ::gdk_colormap_new(visual, FALSE);
|
||||
::gtk_widget_set_colormap(widget, colorMap);
|
||||
#endif
|
||||
|
||||
::gtk_widget_queue_resize(widget);
|
||||
::gtk_widget_set_double_buffered(widget, FALSE);
|
||||
|
||||
glXSwapIntervalEXT = (glXSwapIntervalEXT_t) ::glXGetProcAddressARB(reinterpret_cast <const unsigned char*>("glXSwapIntervalEXT"));
|
||||
|
||||
GTK_GL_DEBUG("initialize::success");
|
||||
}
|
||||
|
||||
void OpenViBE::AdvancedVisualization::GtkGL::uninitialize(GtkWidget * widget)
|
||||
{
|
||||
GTK_GL_DEBUG("uninitialize");
|
||||
|
||||
::Display* display = GDK_SCREEN_XDISPLAY(gtk_widget_get_screen(widget));
|
||||
::GLXContext glRenderingCtx = (GLXContext) g_object_get_data(G_OBJECT(widget), GTK_GL_RENDERING_CONTEXT_NAME);
|
||||
if (!display || !glRenderingCtx)
|
||||
{
|
||||
GTK_GL_WARNING("uninitialize::failed");
|
||||
return;
|
||||
}
|
||||
::glXMakeCurrent(display, None, nullptr);
|
||||
::glXDestroyContext(display, glRenderingCtx);
|
||||
|
||||
GTK_GL_DEBUG("uninitialize::success");
|
||||
}
|
||||
|
||||
void OpenViBE::AdvancedVisualization::GtkGL::preRender(GtkWidget * widget, bool bVerticalSync)
|
||||
{
|
||||
GTK_GL_DEBUG("pre-render");
|
||||
|
||||
::Display* display = GDK_SCREEN_XDISPLAY(gtk_widget_get_screen(widget));
|
||||
::Window window = GDK_WINDOW_XID(gtk_widget_get_window(widget));
|
||||
::GLXContext glRenderingCtx = (GLXContext) g_object_get_data(G_OBJECT(widget), GTK_GL_RENDERING_CONTEXT_NAME);
|
||||
if (!display || !glRenderingCtx)
|
||||
{
|
||||
GTK_GL_WARNING("pre-render::failed");
|
||||
return;
|
||||
}
|
||||
::glXMakeCurrent(display, window, glRenderingCtx);
|
||||
|
||||
// Enable / Disable vsync
|
||||
if (glXSwapIntervalEXT)
|
||||
{
|
||||
glXSwapIntervalEXT(display, ::glXGetCurrentDrawable(), bVerticalSync ? 1 : 0);
|
||||
}
|
||||
|
||||
GTK_GL_DEBUG("pre-render::success");
|
||||
}
|
||||
|
||||
void OpenViBE::AdvancedVisualization::GtkGL::postRender(GtkWidget * widget)
|
||||
{
|
||||
GTK_GL_DEBUG("post-render");
|
||||
|
||||
::Display* display = GDK_SCREEN_XDISPLAY(gtk_widget_get_screen(widget));
|
||||
::Window window = GDK_WINDOW_XID(gtk_widget_get_window(widget));
|
||||
if (!display)
|
||||
{
|
||||
GTK_GL_WARNING("post-render::failed");
|
||||
return;
|
||||
}
|
||||
::glXSwapBuffers(display, window);
|
||||
|
||||
GTK_GL_DEBUG("post-render::success");
|
||||
}
|
||||
|
||||
// ## LINUX ################################################################################################################################################
|
||||
|
||||
#endif
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
/*********************************************************************
|
||||
* Software License Agreement (AGPL-3 License)
|
||||
*
|
||||
* OpenViBE Designer
|
||||
* Based on OpenViBE V1.1.0, Copyright (C) Inria, 2006-2015
|
||||
* Copyright (C) Inria, 2015-2017,V1.0
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace AdvancedVisualization {
|
||||
namespace GtkGL {
|
||||
void initialize(GtkWidget* widget);
|
||||
void uninitialize(GtkWidget* widget);
|
||||
|
||||
void preRender(GtkWidget* widget, bool verticalSync = false);
|
||||
void postRender(GtkWidget* widget);
|
||||
} // namespace GtkGL
|
||||
} // namespace AdvancedVisualization
|
||||
} // namespace OpenViBE
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
/*********************************************************************
|
||||
* Software License Agreement (AGPL-3 License)
|
||||
*
|
||||
* OpenViBE Designer
|
||||
* Based on OpenViBE V1.1.0, Copyright (C) Inria, 2006-2015
|
||||
* Copyright (C) Inria, 2015-2017,V1.0
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "m_VisualizationTools.hpp"
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace AdvancedVisualization {
|
||||
|
||||
std::string trim(const std::string& value)
|
||||
{
|
||||
if (value.length() == 0) { return ""; }
|
||||
size_t i = 0;
|
||||
size_t j = value.length() - 1;
|
||||
while (i < value.length() && value[i] == ' ') { i++; }
|
||||
while (j > i && value[j] == ' ') { j--; }
|
||||
return value.substr(i, j - i + 1);
|
||||
}
|
||||
|
||||
CRendererContext& getContext()
|
||||
{
|
||||
static CRendererContext* ctx = new CRendererContext();
|
||||
return *ctx;
|
||||
}
|
||||
|
||||
} // namespace AdvancedVisualization
|
||||
} // namespace OpenViBE
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
/*********************************************************************
|
||||
* Software License Agreement (AGPL-3 License)
|
||||
*
|
||||
* OpenViBE Designer
|
||||
* Based on OpenViBE V1.1.0, Copyright (C) Inria, 2006-2015
|
||||
* Copyright (C) Inria, 2015-2017,V1.0
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "m_defines.hpp"
|
||||
|
||||
#include <mensia/advanced-visualization.hpp>
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace AdvancedVisualization {
|
||||
std::string trim(const std::string& value);
|
||||
CRendererContext& getContext();
|
||||
} // namespace AdvancedVisualization
|
||||
} // namespace OpenViBE
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
/*********************************************************************
|
||||
* Software License Agreement (AGPL-3 License)
|
||||
*
|
||||
* OpenViBE Designer
|
||||
* Based on OpenViBE V1.1.0, Copyright (C) Inria, 2006-2015
|
||||
* Copyright (C) Inria, 2015-2017,V1.0
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
// Temporal coherence definition
|
||||
#define OVP_TypeId_TemporalCoherence OpenViBE::CIdentifier(0x8F02E3F6, 0xFFB00F4B)
|
||||
|
||||
enum class ETemporalCoherence { TimeLocked, Independant };
|
||||
|
||||
#define OV_TypeId_TimeFrequency OpenViBE::CIdentifier(0x5A90816B, 0xFF2AFF72)
|
||||
+221
@@ -0,0 +1,221 @@
|
||||
/*********************************************************************
|
||||
* Software License Agreement (AGPL-3 License)
|
||||
*
|
||||
* OpenViBE Designer
|
||||
* Based on OpenViBE V1.1.0, Copyright (C) Inria, 2006-2015
|
||||
* Copyright (C) Inria, 2015-2017,V1.0
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "m_defines.hpp"
|
||||
|
||||
// #define TARGET_Has_Experimental
|
||||
|
||||
#include "mTBoxAlgorithmStackedContinuousViz.hpp"
|
||||
#include "mTBoxAlgorithmStackedInstantViz.hpp"
|
||||
#include "mTBoxAlgorithmContinuousViz.hpp"
|
||||
#include "mTBoxAlgorithmInstantViz.hpp"
|
||||
#include "mTBoxAlgorithmInstantLoretaViz.hpp"
|
||||
|
||||
#include "ruler/mTRulerAutoType.hpp"
|
||||
#include "ruler/mTRulerPair.hpp"
|
||||
#include "ruler/mTRulerConditionalPair.hpp"
|
||||
#include "ruler/mCRulerConditionIsTimeLocked.hpp"
|
||||
|
||||
#include "ruler/mCRulerProgress.hpp"
|
||||
#include "ruler/mCRulerProgressH.hpp"
|
||||
#include "ruler/mCRulerProgressV.hpp"
|
||||
#include "ruler/mCRulerERPProgress.hpp"
|
||||
|
||||
#include "ruler/mCRulerBottomCount.hpp"
|
||||
#include "ruler/mCRulerBottomERPCount.hpp"
|
||||
#include "ruler/mCRulerBottomERPTime.hpp"
|
||||
#include "ruler/mCRulerBottomFrequency.hpp"
|
||||
#include "ruler/mCRulerBottomPercent.hpp"
|
||||
#include "ruler/mCRulerBottomTexture.hpp"
|
||||
#include "ruler/mCRulerBottomTime.hpp"
|
||||
|
||||
#include "ruler/mCRulerLeftChannelNames.hpp"
|
||||
#include "ruler/mCRulerLeftTexture.hpp"
|
||||
|
||||
#include "ruler/mCRulerRightCount.hpp"
|
||||
#include "ruler/mCRulerRightFrequency.hpp"
|
||||
#include "ruler/mCRulerRightMonoScale.hpp"
|
||||
#include "ruler/mCRulerRightTexture.hpp"
|
||||
#include "ruler/mCRulerRightScale.hpp"
|
||||
#include "ruler/mCRulerRightLabels.hpp"
|
||||
|
||||
#include <system/ovCTime.h>
|
||||
|
||||
#include <ctime>
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace AdvancedVisualization {
|
||||
// Prototype to create and release final renderer instances from the renderer API
|
||||
|
||||
template <ERendererType TType, bool TStimulation = false>
|
||||
class TRendererProto
|
||||
{
|
||||
public:
|
||||
|
||||
static IRenderer* create() { return IRenderer::create(TType, TStimulation); }
|
||||
static void release(IRenderer* renderer) { return IRenderer::release(renderer); }
|
||||
};
|
||||
|
||||
// Type definitions of our OpenViBE boxes
|
||||
|
||||
typedef TBoxAlgorithmContinuousVizDesc<TRendererProto<ERendererType::Bitmap, true>, TRulerPair<
|
||||
CRulerProgressV, TRulerPair<
|
||||
TRulerAutoType<IRuler, TRulerConditionalPair<CRulerBottomTime, CRulerBottomCount, CRulerConditionIsTimeLocked>,
|
||||
IRuler>, TRulerPair<CRulerLeftChannelNames, CRulerRightTexture>>>> bitmap_t;
|
||||
typedef TBoxAlgorithmContinuousVizDesc<TRendererProto<ERendererType::Line, true>, TRulerPair<
|
||||
CRulerProgressV, TRulerPair<
|
||||
TRulerAutoType<IRuler, TRulerConditionalPair<CRulerBottomTime, CRulerBottomCount, CRulerConditionIsTimeLocked>,
|
||||
IRuler>, TRulerPair<CRulerLeftChannelNames, CRulerRightScale>>>> oscilloscope_t;
|
||||
typedef TBoxAlgorithmContinuousVizDesc<TRendererProto<ERendererType::Bars, true>, TRulerPair<
|
||||
CRulerProgressV, TRulerPair<
|
||||
TRulerAutoType<IRuler, TRulerConditionalPair<CRulerBottomTime, CRulerBottomCount, CRulerConditionIsTimeLocked>,
|
||||
IRuler>, TRulerPair<CRulerLeftChannelNames, CRulerRightScale>>>> bars_t;
|
||||
typedef TBoxAlgorithmContinuousVizDesc<TRendererProto<ERendererType::MultiLine, true>, TRulerPair<
|
||||
CRulerProgressV, TRulerPair<
|
||||
TRulerAutoType<IRuler, TRulerConditionalPair<CRulerBottomTime, CRulerBottomCount, CRulerConditionIsTimeLocked>,
|
||||
IRuler>, TRulerPair<TRulerPair<CRulerLeftChannelNames, CRulerLeftTexture>, CRulerRightMonoScale>>>> MOscilloscope;
|
||||
typedef TBoxAlgorithmContinuousVizDesc<TRendererProto<ERendererType::XYZPlot>> xyz_plot_t;
|
||||
|
||||
typedef TBoxAlgorithmInstantVizDesc<TRendererProto<ERendererType::Bitmap>, TRulerPair<
|
||||
CRulerERPProgress, TRulerPair<
|
||||
TRulerAutoType<CRulerBottomERPCount, CRulerBottomERPTime, CRulerBottomFrequency>, TRulerPair<
|
||||
CRulerLeftChannelNames, CRulerRightTexture>>>> i_bitmap_t;
|
||||
typedef TBoxAlgorithmInstantVizDesc<TRendererProto<ERendererType::Line>, TRulerPair<
|
||||
CRulerERPProgress, TRulerPair<
|
||||
TRulerAutoType<CRulerBottomERPCount, CRulerBottomERPTime, CRulerBottomFrequency>, TRulerPair<
|
||||
CRulerLeftChannelNames, CRulerRightScale>>>> i_oscilloscope_t;
|
||||
typedef TBoxAlgorithmInstantVizDesc<TRendererProto<ERendererType::Bars>, TRulerPair<
|
||||
CRulerERPProgress, TRulerPair<
|
||||
TRulerAutoType<CRulerBottomERPCount, CRulerBottomERPTime, CRulerBottomFrequency>, TRulerPair<
|
||||
CRulerLeftChannelNames, CRulerRightScale>>>> i_bars_t;
|
||||
typedef TBoxAlgorithmInstantVizDesc<TRendererProto<ERendererType::MultiLine>, TRulerPair<
|
||||
CRulerERPProgress, TRulerPair<
|
||||
TRulerAutoType<CRulerBottomERPCount, CRulerBottomERPTime, CRulerBottomFrequency>, TRulerPair<
|
||||
TRulerPair<CRulerLeftChannelNames, CRulerLeftTexture>, CRulerRightMonoScale>>>> MIOscilloscope;
|
||||
typedef TBoxAlgorithmInstantVizDesc<TRendererProto<ERendererType::XYZPlot>> i_xyz_plot_t;
|
||||
|
||||
typedef TBoxAlgorithmStackedContinuousVizDesc<false, true, TRendererProto<ERendererType::Bitmap, true>, TRulerPair<
|
||||
TRulerAutoType<CRulerBottomERPCount, CRulerBottomERPTime, CRulerBottomFrequency>, TRulerPair<
|
||||
CRulerLeftChannelNames, CRulerProgressH>>> sv_bitmap_t;
|
||||
typedef TBoxAlgorithmStackedContinuousVizDesc<true, true, TRendererProto<ERendererType::Bitmap, true>, TRulerPair<
|
||||
TRulerConditionalPair<CRulerBottomTime, CRulerBottomCount, CRulerConditionIsTimeLocked>, TRulerPair<
|
||||
TRulerAutoType<IRuler, IRuler, CRulerRightFrequency>, TRulerPair<CRulerLeftChannelNames, CRulerProgressV>>
|
||||
>> sh_bitmap_t;
|
||||
typedef TBoxAlgorithmStackedInstantVizDesc<true, TRendererProto<ERendererType::Bitmap, true>, TRulerPair<
|
||||
CRulerBottomERPTime, TRulerPair<CRulerRightLabels<1>, TRulerPair<CRulerLeftChannelNames, CRulerProgressV>>>>
|
||||
si_bitmap_t;
|
||||
|
||||
typedef TBoxAlgorithmInstantVizDesc<TRendererProto<ERendererType::Topography2D>, CRulerBottomTexture> topography_2d_t;
|
||||
typedef TBoxAlgorithmInstantVizDesc<TRendererProto<ERendererType::Topography3D>, CRulerBottomTexture> topography_3d_t;
|
||||
typedef TBoxAlgorithmInstantVizDesc<TRendererProto<ERendererType::Loreta>, CRulerBottomTexture, TBoxAlgorithmInstantLoretaViz> loreta_t;
|
||||
typedef TBoxAlgorithmInstantVizDesc<TRendererProto<ERendererType::Cube>, CRulerBottomTexture> cubes_t;
|
||||
|
||||
OVP_Declare_Begin()
|
||||
context.getTypeManager().registerEnumerationType(OVP_TypeId_TemporalCoherence, "Temporal Coherence");
|
||||
context.getTypeManager().registerEnumerationEntry(OVP_TypeId_TemporalCoherence, "Time Locked", size_t(ETemporalCoherence::TimeLocked));
|
||||
context.getTypeManager().registerEnumerationEntry(OVP_TypeId_TemporalCoherence, "Independant", size_t(ETemporalCoherence::Independant));
|
||||
|
||||
OVP_Declare_New(bitmap_t("Continuous bitmap_t", CIdentifier(0x0BE99978487D3DC6), CIdentifier(0x9E1CD34586569E7E), "0.0.0", "0.0.0",
|
||||
CParameterSet(I_Matrix,I_Stimulations, S_ChannelLocalisation, S_TemporalCoherence, S_TimeScale, S_ElementCount, S_DataScale, S_Caption, S_ColorGradient,
|
||||
P_None),
|
||||
"Displays the input matrices as a map of colored tiles, or bitmap, continuously.", ""))
|
||||
|
||||
OVP_Declare_New(oscilloscope_t("Continuous oscilloscope_t", CIdentifier(0x6D63896D86685134), CIdentifier(0x0842BCD1D53C1C89), "0.0.0", "0.0.0",
|
||||
CParameterSet(I_Signal, I_Stimulations, S_ChannelLocalisation, S_TemporalCoherence, S_TimeScale, S_ElementCount, S_DataPositive, S_DataScale, S_Caption,
|
||||
S_Translucency, S_Color, P_None),
|
||||
"Displays the input matrices as a series of curves.\nChannels are vertically distributed.",""))
|
||||
|
||||
OVP_Declare_New(bars_t("Continuous bars_t", CIdentifier(0xE6B2C8A8B43DE2C3), CIdentifier(0x24510F3EFCBE83A2), "0.0.0", "0.0.0",
|
||||
CParameterSet(I_Matrix,I_Stimulations, S_ChannelLocalisation, S_TemporalCoherence, S_TimeScale, S_ElementCount, S_DataPositive, S_DataScale, S_Caption,
|
||||
S_Translucency,S_ColorGradient, P_None),
|
||||
"Displays the input matrices as a series of colored bars.\nChannels are vertically distributed.",""))
|
||||
|
||||
OVP_Declare_New(MOscilloscope("Continuous Multi oscilloscope_t", CIdentifier(0xD4C4DCEE6F5D47E1), CIdentifier(0xA927FB20C4089F99), "0.0.0", "0.0.0",
|
||||
CParameterSet(I_Signal, I_Stimulations, S_ChannelLocalisation, S_TemporalCoherence, S_TimeScale, S_ElementCount, S_DataPositive, S_DataScale,
|
||||
S_Caption, S_Translucency, S_ColorGradient, P_None),
|
||||
"Displays the input matrices as a series of curves.\nAll channels are rendered on the same vertical axis, with different colors.", ""))
|
||||
|
||||
OVP_Declare_New(xyz_plot_t("Continuous XYZ Plot", CIdentifier(0xAAFD16CF57DC7138), CIdentifier(0xDDA9A9D9D04F2C14), "0.0.0", "0.0.0",
|
||||
CParameterSet(I_Signal, S_TemporalCoherence, S_TimeScale, S_ElementCount, S_DataScale, S_Caption, S_Translucency, S_ShowAxis,S_XYZPlotHasDepth,
|
||||
S_ColorGradient, F_FixedChannelOrder, F_FixedChannelSelection, P_None),
|
||||
"Displays the input matrices as a series of points in 2D or 3D space, continuously.", ""))
|
||||
|
||||
|
||||
OVP_Declare_New(i_bitmap_t("Instant bitmap_t", CIdentifier(0x942CDA76A437E83E), CIdentifier(0xF862765845247823), "0.0.0", "0.0.0",
|
||||
CParameterSet(I_Spectrum, S_ChannelLocalisation, S_DataScale, S_Caption, S_ColorGradient, P_None),
|
||||
"Displays each and every input matrix as a map of colored tiles, or bitmap, instantly.", ""))
|
||||
|
||||
OVP_Declare_New(i_oscilloscope_t("Instant oscilloscope_t", CIdentifier(0x1207B96D19A805B4), CIdentifier(0x997B654D0CDB3102), "0.0.0", "0.0.0",
|
||||
CParameterSet(I_Signal, S_ChannelLocalisation, S_DataPositive, S_DataScale, S_Caption, S_Translucency, S_Color, F_CanAddInput, P_None),
|
||||
"Displays each and every input matrix as a series of curves, instantly.\nChannels are vertically distributed.", ""))
|
||||
|
||||
OVP_Declare_New(i_bars_t("Instant bars_t", CIdentifier(0xD401BE1F25F01E4E), CIdentifier(0xECB4608196DA0D49), "0.0.0", "0.0.0",
|
||||
CParameterSet(I_Spectrum,S_ChannelLocalisation, S_DataPositive, S_DataScale, S_Caption, S_Translucency, S_ColorGradient, P_None),
|
||||
"Displays each and every input matrix as a series of colored bars, instantly.\nChannels are vertically distributed.", ""))
|
||||
|
||||
OVP_Declare_New(MIOscilloscope("Instant Multi oscilloscope_t", CIdentifier(0x4F142FE87C7773E3), CIdentifier(0x072B75A9C28D588A), "0.0.0", "0.0.0",
|
||||
CParameterSet(I_Signal, S_ChannelLocalisation, S_DataPositive, S_DataScale, S_Caption, S_Translucency, S_ColorGradient, P_None),
|
||||
"Displays each and every input matrix as a series of curves, instantly.\nAll channels are rendered on the same vertical axis, with different colors.",
|
||||
""))
|
||||
|
||||
OVP_Declare_New(i_xyz_plot_t("Instant XYZ Plot", CIdentifier(0x1353BED819EC86A5), CIdentifier(0xDB19374A41A22DD3), "0.0.0", "0.0.0",
|
||||
CParameterSet(I_Signal, S_DataScale, S_Caption, S_Translucency, S_ShowAxis, S_XYZPlotHasDepth, S_ColorGradient,F_FixedChannelOrder,
|
||||
F_FixedChannelSelection, P_None),
|
||||
"Displays the input matrices as a series of points in 2D or 3D space, instantly.", ""))
|
||||
|
||||
|
||||
OVP_Declare_New(sv_bitmap_t("Stacked bitmap_t (Vertical)", CIdentifier(0x93F400CF9F6C5AFD), CIdentifier(0x9926A761BA82D233), "0.0.0", "0.0.0",
|
||||
CParameterSet(I_Matrix, I_Stimulations, S_ChannelLocalisation, S_TemporalCoherence, S_TimeScale, S_ElementCount, S_DataScale, S_Caption, S_ColorGradient
|
||||
,P_None),
|
||||
"Displays the input matrices as a map of colored tiles, or bitmap, continuously.\nAll the bitmaps are stacked vertically, starting from the bottom edge of the window"
|
||||
, ""))
|
||||
|
||||
OVP_Declare_New(sh_bitmap_t("Stacked bitmap_t (Horizontal)", CIdentifier(0x6B22DC653AB0EC0F), CIdentifier(0x7B0DDB65FDC51488), "0.0.0", "0.0.0",
|
||||
CParameterSet(I_Matrix, I_Stimulations, S_ChannelLocalisation, S_TemporalCoherence, S_TimeScale, S_ElementCount, S_DataScale, S_Caption, S_ColorGradient
|
||||
, P_None),
|
||||
"Displays the input matrices as a map of colored tiles, or bitmap, continuously.\nAll the bitmaps are stacked horizontally, starting from the left edge of the window"
|
||||
, ""))
|
||||
|
||||
OVP_Declare_New(si_bitmap_t("Instant bitmap_t (3D Stream)", CIdentifier(0x0C61E7632A5C3178), CIdentifier(0xC3CC8B43EE985C1D), "0.1.0", "0.1.0",
|
||||
CParameterSet(I_TimeFrequency, I_Stimulations, S_ChannelLocalisation, S_DataScale, S_Caption, S_ColorGradient, P_None),
|
||||
"Displays the input matrices as a map of colored tiles, or bitmap, continuously.", ""))
|
||||
|
||||
OVP_Declare_New(topography_2d_t("2D Topography", CIdentifier(0x0A0C12A7E695F3FB), CIdentifier(0x7C3A05B8C45386F8), "0.0.0", "0.0.0",
|
||||
CParameterSet(I_Signal, S_ChannelLocalisation, S_DataScale, S_Caption, S_ColorGradient, F_FixedChannelOrder, P_None),
|
||||
"The input is mapped to a 2 dimensional plane model of the scalp surface, using a color gradient and interpolation.", ""))
|
||||
|
||||
OVP_Declare_New(topography_3d_t("3D Topography", CIdentifier(0xA3F1CF20DEC477F3), CIdentifier(0xC709EA84B577D910), "0.0.0", "0.0.0",
|
||||
CParameterSet(I_Signal,S_ChannelLocalisation, S_DataScale, S_Caption, S_ColorGradient, F_FixedChannelOrder, P_None),
|
||||
"The input is mapped to a 3D model of the scalp, using a color gradient and interpolation.", ""))
|
||||
|
||||
OVP_Declare_New(cubes_t("3D cubes_t", CIdentifier(0x6307469DF938EF27), CIdentifier(0xE028305D4ACF9D1A), "0.0.0", "0.0.0",
|
||||
CParameterSet(I_Signal,S_ChannelLocalisation, S_DataScale, S_Caption, S_ColorGradient, F_FixedChannelOrder, P_None),
|
||||
"The input is mapped to a 3D representation of the EEG setup where electrodes are symbolized with cubes,\nusing a color gradient and interpolation.", ""
|
||||
))
|
||||
|
||||
OVP_Declare_New(loreta_t("3D Tomographic Visualization", CIdentifier(0xD5F62E7685E0D97C), CIdentifier(0xFD0826035C47E922), "0.0.0", "0.0.0",
|
||||
CParameterSet(I_Signal, S_DataScale, S_Caption, S_Translucency, S_ColorGradient, F_FixedChannelOrder, P_None),
|
||||
"Displays sources activity by mapping it to voxels in a 3D model of the scalp.", ""))
|
||||
|
||||
OVP_Declare_End()
|
||||
|
||||
} // namespace AdvancedVisualization
|
||||
} // namespace OpenViBE
|
||||
+80
@@ -0,0 +1,80 @@
|
||||
/*********************************************************************
|
||||
* Software License Agreement (AGPL-3 License)
|
||||
*
|
||||
* OpenViBE Designer
|
||||
* Based on OpenViBE V1.1.0, Copyright (C) Inria, 2006-2015
|
||||
* Copyright (C) Inria, 2015-2017,V1.0
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "../mIRuler.hpp"
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace AdvancedVisualization {
|
||||
class CRulerBottomCount : public IRuler
|
||||
{
|
||||
public:
|
||||
|
||||
void renderBottom(GtkWidget* widget) override
|
||||
{
|
||||
if (m_renderer == nullptr) { return; }
|
||||
if (m_renderer->getSampleCount() == 0) { return; }
|
||||
if (m_renderer->getHistoryCount() == 0) { return; }
|
||||
if (m_renderer->getHistoryIndex() == 0) { return; }
|
||||
|
||||
const size_t nSample = m_renderer->getSampleCount();
|
||||
const size_t historyIdx = m_renderer->getHistoryIndex();
|
||||
|
||||
|
||||
const size_t leftIdx1 = historyIdx - historyIdx % nSample;
|
||||
const size_t leftIdx2 = historyIdx;
|
||||
const size_t rightIdx1 = leftIdx2 - nSample;
|
||||
const size_t rightIdx2 = leftIdx1;
|
||||
|
||||
std::vector<double> range1 = splitRange(double(leftIdx1), double(leftIdx1 + nSample), 10);
|
||||
std::vector<double> range2 = splitRange(double(rightIdx1), double(rightIdx1 + nSample), 10);
|
||||
|
||||
gint w, h, x;
|
||||
|
||||
gdk_drawable_get_size(widget->window, &w, &h);
|
||||
GdkGC* drawGC = gdk_gc_new(widget->window);
|
||||
for (const auto& i : range1)
|
||||
{
|
||||
if (i >= leftIdx1 && i < leftIdx2)
|
||||
{
|
||||
x = gint(((i - leftIdx1) / nSample) * w);
|
||||
PangoLayout* layout = gtk_widget_create_pango_layout(widget, getLabel(i).c_str());
|
||||
gdk_draw_layout(widget->window, drawGC, x, 5, layout);
|
||||
gdk_draw_line(widget->window, drawGC, x, 0, x, 3);
|
||||
g_object_unref(layout);
|
||||
}
|
||||
}
|
||||
for (const auto& i : range2)
|
||||
{
|
||||
if (i >= rightIdx1 && i < rightIdx2)
|
||||
{
|
||||
x = gint(((i + nSample - leftIdx1) / nSample) * w);
|
||||
PangoLayout* layout = gtk_widget_create_pango_layout(widget, getLabel(i).c_str());
|
||||
gdk_draw_layout(widget->window, drawGC, x, 5, layout);
|
||||
gdk_draw_line(widget->window, drawGC, x, 0, x, 3);
|
||||
g_object_unref(layout);
|
||||
}
|
||||
}
|
||||
g_object_unref(drawGC);
|
||||
}
|
||||
};
|
||||
} // namespace AdvancedVisualization
|
||||
} // namespace OpenViBE
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
/*********************************************************************
|
||||
* Software License Agreement (AGPL-3 License)
|
||||
*
|
||||
* OpenViBE Designer
|
||||
* Based on OpenViBE V1.1.0, Copyright (C) Inria, 2006-2015
|
||||
* Copyright (C) Inria, 2015-2017,V1.0
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "../mIRuler.hpp"
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace AdvancedVisualization {
|
||||
class CRulerBottomERPCount : public IRuler
|
||||
{
|
||||
public:
|
||||
|
||||
void renderBottom(GtkWidget* widget) override
|
||||
{
|
||||
if (m_renderer == nullptr) { return; }
|
||||
if (m_renderer->getSampleCount() == 0) { return; }
|
||||
if (m_renderer->getHistoryCount() == 0) { return; }
|
||||
if (m_renderer->getHistoryIndex() == 0) { return; }
|
||||
|
||||
const size_t nSample = m_renderer->getSampleCount();
|
||||
const double duration = nSample * 1.;
|
||||
|
||||
std::vector<double> range = splitRange(0, duration, 10);
|
||||
|
||||
gint w, h;
|
||||
|
||||
gdk_drawable_get_size(widget->window, &w, &h);
|
||||
GdkGC* drawGC = gdk_gc_new(widget->window);
|
||||
for (const auto& i : range)
|
||||
{
|
||||
const gint x = gint((i / duration) * w);
|
||||
PangoLayout* layout = gtk_widget_create_pango_layout(widget, getLabel(i).c_str());
|
||||
gdk_draw_layout(widget->window, drawGC, x, 5, layout);
|
||||
gdk_draw_line(widget->window, drawGC, x, 0, x, 3);
|
||||
g_object_unref(layout);
|
||||
}
|
||||
g_object_unref(drawGC);
|
||||
}
|
||||
};
|
||||
} // namespace AdvancedVisualization
|
||||
} // namespace OpenViBE
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
/*********************************************************************
|
||||
* Software License Agreement (AGPL-3 License)
|
||||
*
|
||||
* OpenViBE Designer
|
||||
* Based on OpenViBE V1.1.0, Copyright (C) Inria, 2006-2015
|
||||
* Copyright (C) Inria, 2015-2017,V1.0
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "../mIRuler.hpp"
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace AdvancedVisualization {
|
||||
class CRulerBottomERPTime : public IRuler
|
||||
{
|
||||
public:
|
||||
|
||||
void renderBottom(GtkWidget* widget) override
|
||||
{
|
||||
if (m_renderer == nullptr) { return; }
|
||||
if (m_renderer->getSampleCount() == 0) { return; }
|
||||
if (m_renderer->getHistoryCount() == 0) { return; }
|
||||
if (m_renderer->getHistoryIndex() == 0) { return; }
|
||||
|
||||
const size_t nSample = m_renderer->getSampleCount();
|
||||
const uint64_t sampleDuration = m_rendererCtx->getSampleDuration();
|
||||
const double duration = double((nSample * sampleDuration) >> 16) / 65536.;
|
||||
|
||||
std::vector<double> range = splitRange(0, duration, 10);
|
||||
|
||||
gint w, h;
|
||||
|
||||
gdk_drawable_get_size(widget->window, &w, &h);
|
||||
GdkGC* drawGC = gdk_gc_new(widget->window);
|
||||
for (const auto& i : range)
|
||||
{
|
||||
const gint x = gint((i / duration) * w);
|
||||
PangoLayout* layout = gtk_widget_create_pango_layout(widget, getLabel(i).c_str());
|
||||
gdk_draw_layout(widget->window, drawGC, x, 5, layout);
|
||||
gdk_draw_line(widget->window, drawGC, x, 0, x, 3);
|
||||
g_object_unref(layout);
|
||||
}
|
||||
g_object_unref(drawGC);
|
||||
}
|
||||
};
|
||||
} // namespace AdvancedVisualization
|
||||
} // namespace OpenViBE
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
/*********************************************************************
|
||||
* Software License Agreement (AGPL-3 License)
|
||||
*
|
||||
* OpenViBE Designer
|
||||
* Based on OpenViBE V1.1.0, Copyright (C) Inria, 2006-2015
|
||||
* Copyright (C) Inria, 2015-2017,V1.0
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "../mIRuler.hpp"
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace AdvancedVisualization {
|
||||
class CRulerBottomFrequency : public IRuler
|
||||
{
|
||||
public:
|
||||
|
||||
void renderBottom(GtkWidget* widget) override
|
||||
{
|
||||
const auto scale = float(m_rendererCtx->getSpectrumFrequencyRange());
|
||||
if (m_lastScale != scale)
|
||||
{
|
||||
m_range = splitRange(0, scale);
|
||||
m_lastScale = scale;
|
||||
}
|
||||
|
||||
gint w, h;
|
||||
|
||||
gdk_drawable_get_size(widget->window, &w, &h);
|
||||
GdkGC* drawGC = gdk_gc_new(widget->window);
|
||||
for (const auto& i : m_range)
|
||||
{
|
||||
const gint x = gint((i / scale) * w);
|
||||
PangoLayout* layout = gtk_widget_create_pango_layout(widget, getLabel(i).c_str());
|
||||
gdk_draw_layout(widget->window, drawGC, x, 5, layout);
|
||||
gdk_draw_line(widget->window, drawGC, x, 0, x, 3);
|
||||
g_object_unref(layout);
|
||||
}
|
||||
g_object_unref(drawGC);
|
||||
}
|
||||
|
||||
protected:
|
||||
float m_lastScale = 0;
|
||||
std::vector<double> m_range;
|
||||
};
|
||||
} // namespace AdvancedVisualization
|
||||
} // namespace OpenViBE
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
/*********************************************************************
|
||||
* Software License Agreement (AGPL-3 License)
|
||||
*
|
||||
* OpenViBE Designer
|
||||
* Based on OpenViBE V1.1.0, Copyright (C) Inria, 2006-2015
|
||||
* Copyright (C) Inria, 2015-2017,V1.0
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "../mIRuler.hpp"
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace AdvancedVisualization {
|
||||
class CRulerBottomPercent : public IRuler
|
||||
{
|
||||
public:
|
||||
|
||||
void renderBottom(GtkWidget* widget) override
|
||||
{
|
||||
gint w, h;
|
||||
gint lw, lh;
|
||||
|
||||
gdk_drawable_get_size(widget->window, &w, &h);
|
||||
GdkGC* drawGC = gdk_gc_new(widget->window);
|
||||
for (int i = 0; i <= 10; i += 2)
|
||||
{
|
||||
const gint x = (i * (w - 1)) / 10;
|
||||
const std::string label = (std::to_string(i * 10) + "%");
|
||||
PangoLayout* layout = gtk_widget_create_pango_layout(widget, label.c_str());
|
||||
pango_layout_get_size(layout, &lw, &lh);
|
||||
lw /= PANGO_SCALE;
|
||||
lh /= PANGO_SCALE;
|
||||
gdk_draw_layout(widget->window, drawGC, x, 4, layout);
|
||||
gdk_draw_line(widget->window, drawGC, x, 0, x, 3);
|
||||
g_object_unref(layout);
|
||||
}
|
||||
g_object_unref(drawGC);
|
||||
}
|
||||
};
|
||||
} // namespace AdvancedVisualization
|
||||
} // namespace OpenViBE
|
||||
+90
@@ -0,0 +1,90 @@
|
||||
/*********************************************************************
|
||||
* Software License Agreement (AGPL-3 License)
|
||||
*
|
||||
* OpenViBE Designer
|
||||
* Based on OpenViBE V1.1.0, Copyright (C) Inria, 2006-2015
|
||||
* Copyright (C) Inria, 2015-2017,V1.0
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "mCRulerTexture.hpp"
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace AdvancedVisualization {
|
||||
class CRulerBottomTexture : public CRulerTexture
|
||||
{
|
||||
public:
|
||||
|
||||
void render() override
|
||||
|
||||
{
|
||||
this->preRender();
|
||||
|
||||
glColor4f(0, 0, 0, m_blackAlpha);
|
||||
glBegin(GL_QUADS);
|
||||
glTexCoord1f(0);
|
||||
glVertex2f(0, 0.00F);
|
||||
glVertex2f(0, 0.05F);
|
||||
glTexCoord1f(1);
|
||||
glVertex2f(1, 0.05F);
|
||||
glVertex2f(1, 0.00F);
|
||||
glEnd();
|
||||
|
||||
glColor4f(1, 1, 1, m_whiteAlpha);
|
||||
glBegin(GL_QUADS);
|
||||
glTexCoord1f(0);
|
||||
glVertex2f(0, 0.00F);
|
||||
glVertex2f(0, 0.04F);
|
||||
glTexCoord1f(1);
|
||||
glVertex2f(1, 0.04F);
|
||||
glVertex2f(1, 0.00F);
|
||||
glEnd();
|
||||
|
||||
this->postRender();
|
||||
}
|
||||
|
||||
void renderBottom(GtkWidget* widget) override
|
||||
{
|
||||
const float scale = 1.F / m_rendererCtx->getScale();
|
||||
if (m_lastScale != scale)
|
||||
{
|
||||
m_range = splitRange(-scale * .5, scale * .5);
|
||||
m_lastScale = scale;
|
||||
}
|
||||
|
||||
gint w, h;
|
||||
gint lw, lh;
|
||||
|
||||
gdk_drawable_get_size(widget->window, &w, &h);
|
||||
GdkGC* drawGC = gdk_gc_new(widget->window);
|
||||
for (const auto& i : m_range)
|
||||
{
|
||||
PangoLayout* layout = gtk_widget_create_pango_layout(widget, getLabel(i).c_str());
|
||||
pango_layout_get_size(layout, &lw, &lh);
|
||||
lw /= PANGO_SCALE;
|
||||
lh /= PANGO_SCALE;
|
||||
gdk_draw_layout(widget->window, drawGC, gint((.5 + i / scale) * w - lw * .5), 0, layout);
|
||||
g_object_unref(layout);
|
||||
}
|
||||
g_object_unref(drawGC);
|
||||
}
|
||||
|
||||
protected:
|
||||
float m_lastScale = 0;
|
||||
std::vector<double> m_range;
|
||||
};
|
||||
} // namespace AdvancedVisualization
|
||||
} // namespace OpenViBE
|
||||
+85
@@ -0,0 +1,85 @@
|
||||
/*********************************************************************
|
||||
* Software License Agreement (AGPL-3 License)
|
||||
*
|
||||
* OpenViBE Designer
|
||||
* Based on OpenViBE V1.1.0, Copyright (C) Inria, 2006-2015
|
||||
* Copyright (C) Inria, 2015-2017,V1.0
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "../mIRuler.hpp"
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace AdvancedVisualization {
|
||||
class CRulerBottomTime : public IRuler
|
||||
{
|
||||
public:
|
||||
|
||||
void renderBottom(GtkWidget* widget) override
|
||||
{
|
||||
if (m_renderer == nullptr) { return; }
|
||||
if (m_renderer->getSampleCount() == 0) { return; }
|
||||
if (m_renderer->getHistoryCount() == 0) { return; }
|
||||
if (m_renderer->getHistoryIndex() == 0) { return; }
|
||||
|
||||
const size_t nSample = m_renderer->getSampleCount();
|
||||
const size_t historyIdx = m_renderer->getHistoryIndex();
|
||||
const uint64_t sampleDuration = m_rendererCtx->getSampleDuration();
|
||||
|
||||
const size_t leftIdx = historyIdx - historyIdx % nSample;
|
||||
const size_t midIdx = historyIdx;
|
||||
double startTime = double((leftIdx * sampleDuration) >> 16) / 65536.;
|
||||
double midTime = double((midIdx * sampleDuration) >> 16) / 65536.;
|
||||
const double duration = double((nSample * sampleDuration) >> 16) / 65536.;
|
||||
|
||||
const double offset = (m_renderer->getTimeOffset() >> 16) / 65536.;
|
||||
startTime += offset;
|
||||
midTime += offset;
|
||||
|
||||
std::vector<double> range1 = this->splitRange(startTime - duration, startTime, 10);
|
||||
std::vector<double> range2 = this->splitRange(startTime, startTime + duration, 10);
|
||||
|
||||
gint w, h, x;
|
||||
|
||||
gdk_drawable_get_size(widget->window, &w, &h);
|
||||
GdkGC* drawGC = gdk_gc_new(widget->window);
|
||||
for (const auto& i : range1)
|
||||
{
|
||||
if (i >= 0 && i + duration > midTime)
|
||||
{
|
||||
x = gint(((i + duration - startTime) / duration) * w);
|
||||
PangoLayout* layout = gtk_widget_create_pango_layout(widget, getLabel(i).c_str());
|
||||
gdk_draw_layout(widget->window, drawGC, x, 5, layout);
|
||||
gdk_draw_line(widget->window, drawGC, x, 0, x, 3);
|
||||
g_object_unref(layout);
|
||||
}
|
||||
}
|
||||
for (const auto& i : range2)
|
||||
{
|
||||
if (i >= 0 && i < midTime)
|
||||
{
|
||||
x = gint(((i - startTime) / duration) * w);
|
||||
PangoLayout* layout = gtk_widget_create_pango_layout(widget, getLabel(i).c_str());
|
||||
gdk_draw_layout(widget->window, drawGC, x, 5, layout);
|
||||
gdk_draw_line(widget->window, drawGC, x, 0, x, 3);
|
||||
g_object_unref(layout);
|
||||
}
|
||||
}
|
||||
g_object_unref(drawGC);
|
||||
}
|
||||
};
|
||||
} // namespace AdvancedVisualization
|
||||
} // namespace OpenViBE
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
/*********************************************************************
|
||||
* Software License Agreement (AGPL-3 License)
|
||||
*
|
||||
* OpenViBE Designer
|
||||
* Based on OpenViBE V1.1.0, Copyright (C) Inria, 2006-2015
|
||||
* Copyright (C) Inria, 2015-2017,V1.0
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "../mIRuler.hpp"
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace AdvancedVisualization {
|
||||
class CRulerConditionIsTimeLocked : public IRuler
|
||||
{
|
||||
public:
|
||||
|
||||
CRulerConditionIsTimeLocked() : m_rendererCtx(nullptr), m_renderer(nullptr) { }
|
||||
|
||||
void setRendererContext(const CRendererContext* ctx) override { m_rendererCtx = ctx; }
|
||||
void setRenderer(const IRenderer* renderer) override { m_renderer = renderer; }
|
||||
|
||||
bool operator()() const { return m_rendererCtx->isTimeLocked(); }
|
||||
|
||||
protected:
|
||||
const CRendererContext* m_rendererCtx;
|
||||
const IRenderer* m_renderer;
|
||||
};
|
||||
} // namespace AdvancedVisualization
|
||||
} // namespace OpenViBE
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
/*********************************************************************
|
||||
* Software License Agreement (AGPL-3 License)
|
||||
*
|
||||
* OpenViBE Designer
|
||||
* Based on OpenViBE V1.1.0, Copyright (C) Inria, 2006-2015
|
||||
* Copyright (C) Inria, 2015-2017,V1.0
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "../mIRuler.hpp"
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace AdvancedVisualization {
|
||||
class CRulerERPProgress : public IRuler
|
||||
{
|
||||
public:
|
||||
|
||||
void render() override
|
||||
{
|
||||
if (m_renderer == nullptr) { return; }
|
||||
if (m_renderer->getSampleCount() == 0) { return; }
|
||||
if (m_renderer->getHistoryCount() == 0) { return; }
|
||||
if (m_renderer->getHistoryIndex() == 0) { return; }
|
||||
|
||||
const float progress = m_rendererCtx->getERPFraction();
|
||||
if (progress != 0 && progress != 1)
|
||||
{
|
||||
glDisable(GL_TEXTURE_1D);
|
||||
|
||||
glLineWidth(4);
|
||||
glColor3f(0, 0, 0);
|
||||
glBegin(GL_LINES);
|
||||
glVertex2f(progress, 0);
|
||||
glVertex2f(progress, 1);
|
||||
glEnd();
|
||||
|
||||
glLineWidth(2);
|
||||
glColor3f(0.25, 1, 0.25);
|
||||
glBegin(GL_LINES);
|
||||
glVertex2f(progress, 0);
|
||||
glVertex2f(progress, 1);
|
||||
glEnd();
|
||||
}
|
||||
}
|
||||
};
|
||||
} // namespace AdvancedVisualization
|
||||
} // namespace OpenViBE
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
/*********************************************************************
|
||||
* Software License Agreement (AGPL-3 License)
|
||||
*
|
||||
* OpenViBE Designer
|
||||
* Based on OpenViBE V1.1.0, Copyright (C) Inria, 2006-2015
|
||||
* Copyright (C) Inria, 2015-2017,V1.0
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "../mIRuler.hpp"
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace AdvancedVisualization {
|
||||
class CRulerLeftChannelNames : public IRuler
|
||||
{
|
||||
public:
|
||||
|
||||
void renderLeft(GtkWidget* widget) override
|
||||
{
|
||||
gint w, h, lw, lh;
|
||||
gdk_drawable_get_size(widget->window, &w, &h);
|
||||
GdkGC* drawGC = gdk_gc_new(widget->window);
|
||||
for (size_t i = 0; i < m_rendererCtx->getSelectedCount(); ++i)
|
||||
{
|
||||
const size_t idx = m_rendererCtx->getSelected(i);
|
||||
const std::string label = (m_rendererCtx->getChannelName(idx) + " (" + std::to_string(idx + 1) + ")");
|
||||
PangoLayout* layout = gtk_widget_create_pango_layout(widget, label.c_str());
|
||||
pango_layout_get_size(layout, &lw, &lh);
|
||||
lw /= PANGO_SCALE;
|
||||
lh /= PANGO_SCALE;
|
||||
gdk_draw_layout(widget->window, drawGC, w - lw, gint(((i + 0.5) * h) / m_rendererCtx->getSelectedCount() - float(lh) / 2), layout);
|
||||
g_object_unref(layout);
|
||||
}
|
||||
g_object_unref(drawGC);
|
||||
}
|
||||
};
|
||||
} // namespace AdvancedVisualization
|
||||
} // namespace OpenViBE
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
/*********************************************************************
|
||||
* Software License Agreement (AGPL-3 License)
|
||||
*
|
||||
* OpenViBE Designer
|
||||
* Based on OpenViBE V1.1.0, Copyright (C) Inria, 2006-2015
|
||||
* Copyright (C) Inria, 2015-2017,V1.0
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "mCRulerTexture.hpp"
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace AdvancedVisualization {
|
||||
class CRulerLeftTexture : public CRulerTexture
|
||||
{
|
||||
public:
|
||||
|
||||
void render() override
|
||||
|
||||
{
|
||||
this->preRender();
|
||||
|
||||
glColor4f(0, 0, 0, m_blackAlpha);
|
||||
glBegin(GL_QUADS);
|
||||
glTexCoord1f(0);
|
||||
glVertex2f(0.00F, 0);
|
||||
glVertex2f(0.05F, 0);
|
||||
glTexCoord1f(1);
|
||||
glVertex2f(0.05F, 1);
|
||||
glVertex2f(0.00F, 1);
|
||||
glEnd();
|
||||
|
||||
glColor4f(1, 1, 1, m_whiteAlpha);
|
||||
glBegin(GL_QUADS);
|
||||
glTexCoord1f(0);
|
||||
glVertex2f(0.00F, 0);
|
||||
glVertex2f(0.04F, 0);
|
||||
glTexCoord1f(1);
|
||||
glVertex2f(0.04F, 1);
|
||||
glVertex2f(0.00F, 1);
|
||||
glEnd();
|
||||
|
||||
this->postRender();
|
||||
}
|
||||
};
|
||||
} // namespace AdvancedVisualization
|
||||
} // namespace OpenViBE
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
/*********************************************************************
|
||||
* Software License Agreement (AGPL-3 License)
|
||||
*
|
||||
* OpenViBE Designer
|
||||
* Based on OpenViBE V1.1.0, Copyright (C) Inria, 2006-2015
|
||||
* Copyright (C) Inria, 2015-2017,V1.0
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "../mIRuler.hpp"
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace AdvancedVisualization {
|
||||
class CRulerProgress : public IRuler
|
||||
{
|
||||
public:
|
||||
|
||||
virtual void renderFinal(const float progress) = 0;
|
||||
|
||||
void render() override
|
||||
{
|
||||
if (m_renderer == nullptr) { return; }
|
||||
if (m_renderer->getSampleCount() == 0) { return; }
|
||||
if (m_renderer->getHistoryCount() == 0) { return; }
|
||||
if (m_renderer->getHistoryIndex() == 0) { return; }
|
||||
|
||||
const size_t nSample = m_renderer->getSampleCount();
|
||||
const size_t historyIdx = m_renderer->getHistoryIndex();
|
||||
|
||||
const float progress = float(historyIdx - (float(historyIdx) / nSample) * nSample) / nSample;
|
||||
if (progress != 0 && progress != 1) { this->renderFinal(progress); }
|
||||
}
|
||||
};
|
||||
} // namespace AdvancedVisualization
|
||||
} // namespace OpenViBE
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
/*********************************************************************
|
||||
* Software License Agreement (AGPL-3 License)
|
||||
*
|
||||
* OpenViBE Designer
|
||||
* Based on OpenViBE V1.1.0, Copyright (C) Inria, 2006-2015
|
||||
* Copyright (C) Inria, 2015-2017,V1.0
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "mCRulerProgress.hpp"
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace AdvancedVisualization {
|
||||
class CRulerProgressH : public CRulerProgress
|
||||
{
|
||||
public:
|
||||
|
||||
void renderFinal(const float progress) override
|
||||
{
|
||||
const size_t selectedCount = m_rendererCtx->getSelectedCount();
|
||||
glDisable(GL_TEXTURE_1D);
|
||||
glDisable(GL_BLEND);
|
||||
|
||||
glLineWidth(4);
|
||||
glColor3f(0, 0, 0);
|
||||
glBegin(GL_LINES);
|
||||
for (size_t i = 0; i < selectedCount; ++i)
|
||||
{
|
||||
glVertex2f(0, (i + progress) / selectedCount);
|
||||
glVertex2f(1, (i + progress) / selectedCount);
|
||||
}
|
||||
glEnd();
|
||||
|
||||
glLineWidth(2);
|
||||
glColor3f(0.25, 1, 0.25);
|
||||
glBegin(GL_LINES);
|
||||
for (size_t i = 0; i < selectedCount; ++i)
|
||||
{
|
||||
glVertex2f(0, (i + progress) / selectedCount);
|
||||
glVertex2f(1, (i + progress) / selectedCount);
|
||||
}
|
||||
glEnd();
|
||||
}
|
||||
};
|
||||
} // namespace AdvancedVisualization
|
||||
} // namespace OpenViBE
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
/*********************************************************************
|
||||
* Software License Agreement (AGPL-3 License)
|
||||
*
|
||||
* OpenViBE Designer
|
||||
* Based on OpenViBE V1.1.0, Copyright (C) Inria, 2006-2015
|
||||
* Copyright (C) Inria, 2015-2017,V1.0
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "mCRulerProgress.hpp"
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace AdvancedVisualization {
|
||||
class CRulerProgressV : public CRulerProgress
|
||||
{
|
||||
public:
|
||||
|
||||
void renderFinal(const float progress) override
|
||||
{
|
||||
glDisable(GL_TEXTURE_1D);
|
||||
glDisable(GL_BLEND);
|
||||
|
||||
glLineWidth(4);
|
||||
glColor3f(0, 0, 0);
|
||||
glBegin(GL_LINES);
|
||||
glVertex2f(progress, 0);
|
||||
glVertex2f(progress, 1);
|
||||
glEnd();
|
||||
|
||||
glLineWidth(2);
|
||||
glColor3f(0.25, 1, 0.25);
|
||||
glBegin(GL_LINES);
|
||||
glVertex2f(progress, 0);
|
||||
glVertex2f(progress, 1);
|
||||
glEnd();
|
||||
}
|
||||
};
|
||||
} // namespace AdvancedVisualization
|
||||
} // namespace OpenViBE
|
||||
+80
@@ -0,0 +1,80 @@
|
||||
/*********************************************************************
|
||||
* Software License Agreement (AGPL-3 License)
|
||||
*
|
||||
* OpenViBE Designer
|
||||
* Based on OpenViBE V1.1.0, Copyright (C) Inria, 2006-2015
|
||||
* Copyright (C) Inria, 2015-2017,V1.0
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "../mIRuler.hpp"
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace AdvancedVisualization {
|
||||
class CRulerRightCount : public IRuler
|
||||
{
|
||||
public:
|
||||
|
||||
void renderRight(GtkWidget* widget) override
|
||||
{
|
||||
if (m_renderer == nullptr) { return; }
|
||||
if (m_renderer->getSampleCount() == 0) { return; }
|
||||
if (m_renderer->getHistoryCount() == 0) { return; }
|
||||
if (m_renderer->getHistoryIndex() == 0) { return; }
|
||||
|
||||
const size_t nSample = m_renderer->getSampleCount();
|
||||
const size_t historyIdx = m_renderer->getHistoryIndex();
|
||||
|
||||
const size_t leftIdx1 = historyIdx - historyIdx % nSample;
|
||||
const size_t leftIdx2 = historyIdx;
|
||||
const size_t rightIdx1 = leftIdx2 - nSample;
|
||||
const size_t rightIdx2 = leftIdx1;
|
||||
|
||||
std::vector<double> range1 = splitRange(double(leftIdx1), double(leftIdx1 + nSample), 10);
|
||||
std::vector<double> range2 = splitRange(double(rightIdx1), double(rightIdx1 + nSample), 10);
|
||||
|
||||
gint w, h, y;
|
||||
|
||||
gdk_drawable_get_size(widget->window, &w, &h);
|
||||
GdkGC* drawGC = gdk_gc_new(widget->window);
|
||||
|
||||
for (const auto& i : range1)
|
||||
{
|
||||
if (i >= leftIdx1 && i < leftIdx2)
|
||||
{
|
||||
y = gint(((i - leftIdx1) / nSample) * h);
|
||||
PangoLayout* layout = gtk_widget_create_pango_layout(widget, getLabel(i).c_str());
|
||||
gdk_draw_layout(widget->window, drawGC, 5, y, layout);
|
||||
gdk_draw_line(widget->window, drawGC, 0, y, 3, y);
|
||||
g_object_unref(layout);
|
||||
}
|
||||
}
|
||||
for (const auto& i : range2)
|
||||
{
|
||||
if (i >= rightIdx1 && i < rightIdx2)
|
||||
{
|
||||
y = gint(((i + nSample - leftIdx1) / nSample) * h);
|
||||
PangoLayout* layout = gtk_widget_create_pango_layout(widget, getLabel(i).c_str());
|
||||
gdk_draw_layout(widget->window, drawGC, 5, y, layout);
|
||||
gdk_draw_line(widget->window, drawGC, 0, y, 3, y);
|
||||
g_object_unref(layout);
|
||||
}
|
||||
}
|
||||
g_object_unref(drawGC);
|
||||
}
|
||||
};
|
||||
} // namespace AdvancedVisualization
|
||||
} // namespace OpenViBE
|
||||
+68
@@ -0,0 +1,68 @@
|
||||
/*********************************************************************
|
||||
* Software License Agreement (AGPL-3 License)
|
||||
*
|
||||
* OpenViBE Designer
|
||||
* Based on OpenViBE V1.1.0, Copyright (C) Inria, 2006-2015
|
||||
* Copyright (C) Inria, 2015-2017,V1.0
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "../mIRuler.hpp"
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace AdvancedVisualization {
|
||||
class CRulerRightFrequency : public IRuler
|
||||
{
|
||||
public:
|
||||
|
||||
void renderRight(GtkWidget* widget) override
|
||||
{
|
||||
const auto scale = float(m_rendererCtx->getSpectrumFrequencyRange());
|
||||
if (m_lastScale != scale)
|
||||
{
|
||||
m_range = splitRange(0, scale);
|
||||
m_lastScale = scale;
|
||||
}
|
||||
|
||||
gint w, h;
|
||||
gint lw, lh;
|
||||
|
||||
const size_t nChannel = m_rendererCtx->getSelectedCount();
|
||||
for (size_t i = 0; i < nChannel; ++i)
|
||||
{
|
||||
gdk_drawable_get_size(widget->window, &w, &h);
|
||||
GdkGC* drawGC = gdk_gc_new(widget->window);
|
||||
for (const auto& r : m_range)
|
||||
{
|
||||
const gint y = gint((i + r / scale) * (h * 1.F / nChannel));
|
||||
PangoLayout* layout = gtk_widget_create_pango_layout(widget, getLabel(r).c_str());
|
||||
pango_layout_get_size(layout, &lw, &lh);
|
||||
lw /= PANGO_SCALE;
|
||||
lh /= PANGO_SCALE;
|
||||
gdk_draw_layout(widget->window, drawGC, 8, h - y - lh / 2, layout);
|
||||
gdk_draw_line(widget->window, drawGC, 0, h - y, 3, h - y);
|
||||
g_object_unref(layout);
|
||||
}
|
||||
g_object_unref(drawGC);
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
float m_lastScale = 1;
|
||||
std::vector<double> m_range;
|
||||
};
|
||||
} // namespace AdvancedVisualization
|
||||
} // namespace OpenViBE
|
||||
+66
@@ -0,0 +1,66 @@
|
||||
/*********************************************************************
|
||||
* Software License Agreement (AGPL-3 License)
|
||||
*
|
||||
* OpenViBE Designer
|
||||
* Based on OpenViBE V1.1.0, Copyright (C) Inria, 2006-2015
|
||||
* Copyright (C) Inria, 2015-2017,V1.0
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "../mIRuler.hpp"
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace AdvancedVisualization {
|
||||
template <size_t TDim>
|
||||
class CRulerRightLabels : public IRuler
|
||||
{
|
||||
public:
|
||||
|
||||
void renderRight(GtkWidget* widget) override
|
||||
{
|
||||
gint w, h, lw, lh;
|
||||
|
||||
const size_t nChannel = m_rendererCtx->getSelectedCount();
|
||||
for (size_t channel = 0; channel < nChannel; ++channel)
|
||||
{
|
||||
gdk_drawable_get_size(widget->window, &w, &h);
|
||||
GdkGC* drawGC = gdk_gc_new(widget->window);
|
||||
|
||||
const auto labelCount = float(m_rendererCtx->getDimensionLabelCount(TDim));
|
||||
|
||||
gint lastY = gint((channel + (-1 + 0.5F) / labelCount) * (h * 1.F / nChannel));
|
||||
|
||||
for (size_t label = 0; label < m_rendererCtx->getDimensionLabelCount(TDim); ++label)
|
||||
{
|
||||
const gint y = gint((channel + (label + 0.5F) / labelCount) * (h * 1.F / nChannel));
|
||||
if (y >= lastY + 10)
|
||||
{
|
||||
PangoLayout* layout = gtk_widget_create_pango_layout(widget, m_rendererCtx->getDimensionLabel(TDim, label));
|
||||
pango_layout_get_size(layout, &lw, &lh);
|
||||
lw /= PANGO_SCALE;
|
||||
lh /= PANGO_SCALE;
|
||||
gdk_draw_layout(widget->window, drawGC, 8, h - y - lh / 2, layout);
|
||||
gdk_draw_line(widget->window, drawGC, 0, h - y, 3, h - y);
|
||||
g_object_unref(layout);
|
||||
lastY = y;
|
||||
}
|
||||
}
|
||||
g_object_unref(drawGC);
|
||||
}
|
||||
}
|
||||
};
|
||||
} // namespace AdvancedVisualization
|
||||
} // namespace OpenViBE
|
||||
+68
@@ -0,0 +1,68 @@
|
||||
/*********************************************************************
|
||||
* Software License Agreement (AGPL-3 License)
|
||||
*
|
||||
* OpenViBE Designer
|
||||
* Based on OpenViBE V1.1.0, Copyright (C) Inria, 2006-2015
|
||||
* Copyright (C) Inria, 2015-2017,V1.0
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "../mIRuler.hpp"
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace AdvancedVisualization {
|
||||
class CRulerRightMonoScale : public IRuler
|
||||
{
|
||||
public:
|
||||
|
||||
CRulerRightMonoScale() : m_lastScale(-1) { }
|
||||
|
||||
void renderRight(GtkWidget* widget) override
|
||||
{
|
||||
const float scale = 1.F / m_rendererCtx->getScale();
|
||||
if (m_lastScale != scale)
|
||||
{
|
||||
if (m_rendererCtx->isPositiveOnly()) { m_range = splitRange(0, scale, IRuler_SplitCount); }
|
||||
else { m_range = splitRange(-scale * .5, scale * .5, IRuler_SplitCount); }
|
||||
m_lastScale = scale;
|
||||
}
|
||||
|
||||
const float offset = m_rendererCtx->isPositiveOnly() ? 0 : 0.5F;
|
||||
|
||||
gint w, h, lw, lh;
|
||||
|
||||
gdk_drawable_get_size(widget->window, &w, &h);
|
||||
GdkGC* drawGC = gdk_gc_new(widget->window);
|
||||
for (const auto& i : m_range)
|
||||
{
|
||||
PangoLayout* layout = gtk_widget_create_pango_layout(widget, getLabel(i).c_str());
|
||||
pango_layout_get_size(layout, &lw, &lh);
|
||||
lw /= PANGO_SCALE;
|
||||
lh /= PANGO_SCALE;
|
||||
const gint y = gint((1 - (offset + i / scale)) * h);
|
||||
gdk_draw_layout(widget->window, drawGC, 8, y - lh / 2, layout);
|
||||
gdk_draw_line(widget->window, drawGC, 0, y, 3, y);
|
||||
g_object_unref(layout);
|
||||
}
|
||||
g_object_unref(drawGC);
|
||||
}
|
||||
|
||||
protected:
|
||||
float m_lastScale = 1;
|
||||
std::vector<double> m_range;
|
||||
};
|
||||
} // namespace AdvancedVisualization
|
||||
} // namespace OpenViBE
|
||||
+74
@@ -0,0 +1,74 @@
|
||||
/*********************************************************************
|
||||
* Software License Agreement (AGPL-3 License)
|
||||
*
|
||||
* OpenViBE Designer
|
||||
* Based on OpenViBE V1.1.0, Copyright (C) Inria, 2006-2015
|
||||
* Copyright (C) Inria, 2015-2017,V1.0
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "../mIRuler.hpp"
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace AdvancedVisualization {
|
||||
class CRulerRightScale : public IRuler
|
||||
{
|
||||
public:
|
||||
|
||||
CRulerRightScale() : m_lastScale(-1) { }
|
||||
|
||||
void renderRight(GtkWidget* pWidget) override
|
||||
{
|
||||
const size_t nSelected = m_rendererCtx->getSelectedCount();
|
||||
if (!nSelected) { return; }
|
||||
|
||||
const float scale = 1.F / m_rendererCtx->getScale();
|
||||
if (m_lastScale != scale)
|
||||
{
|
||||
if (m_rendererCtx->isPositiveOnly()) { m_range = splitRange(0, scale, IRuler_SplitCount); }
|
||||
else { m_range = splitRange(-scale * .5, scale * .5, IRuler_SplitCount); }
|
||||
m_lastScale = scale;
|
||||
}
|
||||
|
||||
const float offset = m_rendererCtx->isPositiveOnly() ? 0.0F : 0.5F;
|
||||
|
||||
gint w, h, lw, lh;
|
||||
|
||||
gdk_drawable_get_size(pWidget->window, &w, &h);
|
||||
GdkGC* drawGC = gdk_gc_new(pWidget->window);
|
||||
for (size_t i = 0; i < m_rendererCtx->getSelectedCount(); ++i)
|
||||
{
|
||||
for (const auto& j : m_range)
|
||||
{
|
||||
PangoLayout* layout = gtk_widget_create_pango_layout(pWidget, getLabel(j).c_str());
|
||||
pango_layout_get_size(layout, &lw, &lh);
|
||||
lw /= PANGO_SCALE;
|
||||
lh /= PANGO_SCALE;
|
||||
const gint y = gint((1 - (float(i) + offset + j / scale) / nSelected) * h);
|
||||
gdk_draw_layout(pWidget->window, drawGC, 8, y - lh / 2, layout);
|
||||
gdk_draw_line(pWidget->window, drawGC, 0, y, 3, y);
|
||||
g_object_unref(layout);
|
||||
}
|
||||
}
|
||||
g_object_unref(drawGC);
|
||||
}
|
||||
|
||||
protected:
|
||||
float m_lastScale = 1;
|
||||
std::vector<double> m_range;
|
||||
};
|
||||
} // namespace AdvancedVisualization
|
||||
} // namespace OpenViBE
|
||||
+90
@@ -0,0 +1,90 @@
|
||||
/*********************************************************************
|
||||
* Software License Agreement (AGPL-3 License)
|
||||
*
|
||||
* OpenViBE Designer
|
||||
* Based on OpenViBE V1.1.0, Copyright (C) Inria, 2006-2015
|
||||
* Copyright (C) Inria, 2015-2017,V1.0
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "mCRulerTexture.hpp"
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace AdvancedVisualization {
|
||||
class CRulerRightTexture : public CRulerTexture
|
||||
{
|
||||
public:
|
||||
|
||||
CRulerRightTexture() : m_lastScale(-1) { }
|
||||
|
||||
void render() override
|
||||
{
|
||||
this->preRender();
|
||||
|
||||
glColor4f(0, 0, 0, m_blackAlpha);
|
||||
glBegin(GL_QUADS);
|
||||
glTexCoord1f(0);
|
||||
glVertex2f(0.95F, 0);
|
||||
glVertex2f(1.00F, 0);
|
||||
glTexCoord1f(1);
|
||||
glVertex2f(1.00F, 1);
|
||||
glVertex2f(0.95F, 1);
|
||||
glEnd();
|
||||
|
||||
glColor4f(1, 1, 1, m_whiteAlpha);
|
||||
glBegin(GL_QUADS);
|
||||
glTexCoord1f(0);
|
||||
glVertex2f(0.96F, 0);
|
||||
glVertex2f(1.00F, 0);
|
||||
glTexCoord1f(1);
|
||||
glVertex2f(1.00F, 1);
|
||||
glVertex2f(0.96F, 1);
|
||||
glEnd();
|
||||
|
||||
this->postRender();
|
||||
}
|
||||
|
||||
void renderRight(GtkWidget* widget) override
|
||||
{
|
||||
const float scale = 1.F / m_rendererCtx->getScale();
|
||||
if (m_lastScale != scale)
|
||||
{
|
||||
m_range = this->splitRange(-scale * .5, scale * .5);
|
||||
m_lastScale = scale;
|
||||
}
|
||||
|
||||
gint w, h, lw, lh;
|
||||
|
||||
gdk_drawable_get_size(widget->window, &w, &h);
|
||||
GdkGC* drawGC = gdk_gc_new(widget->window);
|
||||
for (const auto& i : m_range)
|
||||
{
|
||||
PangoLayout* layout = gtk_widget_create_pango_layout(widget, getLabel(i).c_str());
|
||||
pango_layout_get_size(layout, &lw, &lh);
|
||||
lw /= PANGO_SCALE;
|
||||
lh /= PANGO_SCALE;
|
||||
gdk_draw_layout(widget->window, drawGC, 0, gint((.5 - i / scale) * h - lh * .5), layout);
|
||||
g_object_unref(layout);
|
||||
}
|
||||
g_object_unref(drawGC);
|
||||
}
|
||||
|
||||
protected:
|
||||
float m_lastScale;
|
||||
std::vector<double> m_range;
|
||||
};
|
||||
} // namespace AdvancedVisualization
|
||||
} // namespace OpenViBE
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
/*********************************************************************
|
||||
* Software License Agreement (AGPL-3 License)
|
||||
*
|
||||
* OpenViBE Designer
|
||||
* Based on OpenViBE V1.1.0, Copyright (C) Inria, 2006-2015
|
||||
* Copyright (C) Inria, 2015-2017,V1.0
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "../mIRuler.hpp"
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace AdvancedVisualization {
|
||||
class CRulerTexture : public IRuler
|
||||
{
|
||||
protected:
|
||||
|
||||
virtual void preRender()
|
||||
|
||||
{
|
||||
glDisable(GL_BLEND);
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glEnable(GL_TEXTURE_1D);
|
||||
glColor3f(1, 1, 1);
|
||||
|
||||
glMatrixMode(GL_TEXTURE);
|
||||
glPushMatrix();
|
||||
glLoadIdentity();
|
||||
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glPushMatrix();
|
||||
glLoadIdentity();
|
||||
}
|
||||
|
||||
virtual void postRender()
|
||||
|
||||
{
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glPopMatrix();
|
||||
|
||||
glMatrixMode(GL_TEXTURE);
|
||||
glPopMatrix();
|
||||
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
}
|
||||
};
|
||||
} // namespace AdvancedVisualization
|
||||
} // namespace OpenViBE
|
||||
+89
@@ -0,0 +1,89 @@
|
||||
/*********************************************************************
|
||||
* Software License Agreement (AGPL-3 License)
|
||||
*
|
||||
* OpenViBE Designer
|
||||
* Based on OpenViBE V1.1.0, Copyright (C) Inria, 2006-2015
|
||||
* Copyright (C) Inria, 2015-2017,V1.0
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "../mIRuler.hpp"
|
||||
#include "../m_VisualizationTools.hpp"
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace AdvancedVisualization {
|
||||
template <class TRulerMatrix, class TRulerSignal, class TRulerSpectrum>
|
||||
class TRulerAutoType : public IRuler
|
||||
{
|
||||
public:
|
||||
|
||||
void setRendererContext(const CRendererContext* ctx) override
|
||||
{
|
||||
IRuler::setRendererContext(ctx);
|
||||
m_rulerSignal.setRendererContext(ctx);
|
||||
m_rulerSpectrum.setRendererContext(ctx);
|
||||
m_rulerMatrix.setRendererContext(ctx);
|
||||
}
|
||||
|
||||
void setRenderer(const IRenderer* renderer) override
|
||||
{
|
||||
IRuler::setRenderer(renderer);
|
||||
m_rulerSignal.setRenderer(renderer);
|
||||
m_rulerSpectrum.setRenderer(renderer);
|
||||
m_rulerMatrix.setRenderer(renderer);
|
||||
}
|
||||
|
||||
void render() override
|
||||
{
|
||||
const CRendererContext::EDataType dataType = m_rendererCtx->getDataType();
|
||||
if (dataType == CRendererContext::EDataType::Signal) { m_rulerSignal.doRender(); }
|
||||
else if (dataType == CRendererContext::EDataType::Spectrum) { m_rulerSpectrum.doRender(); }
|
||||
else { m_rulerMatrix.doRender(); }
|
||||
}
|
||||
|
||||
void renderLeft(GtkWidget* widget) override
|
||||
{
|
||||
const CRendererContext::EDataType dataType = m_rendererCtx->getDataType();
|
||||
if (dataType == CRendererContext::EDataType::Signal) { m_rulerSignal.doRenderLeft(widget); }
|
||||
else if (dataType == CRendererContext::EDataType::Spectrum) { m_rulerSpectrum.doRenderLeft(widget); }
|
||||
else { m_rulerMatrix.doRenderLeft(widget); }
|
||||
}
|
||||
|
||||
void renderRight(GtkWidget* widget) override
|
||||
{
|
||||
const CRendererContext::EDataType dataType = m_rendererCtx->getDataType();
|
||||
if (dataType == CRendererContext::EDataType::Signal) { m_rulerSignal.doRenderRight(widget); }
|
||||
else if (dataType == CRendererContext::EDataType::Spectrum) { m_rulerSpectrum.doRenderRight(widget); }
|
||||
else { m_rulerMatrix.doRenderRight(widget); }
|
||||
}
|
||||
|
||||
void renderBottom(GtkWidget* widget) override
|
||||
{
|
||||
const CRendererContext::EDataType dataType = m_rendererCtx->getDataType();
|
||||
|
||||
if (dataType == CRendererContext::EDataType::Signal) { m_rulerSignal.doRenderBottom(widget); }
|
||||
else if (dataType == CRendererContext::EDataType::Spectrum) { m_rulerSpectrum.doRenderBottom(widget); }
|
||||
else { m_rulerMatrix.doRenderBottom(widget); }
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
TRulerMatrix m_rulerMatrix;
|
||||
TRulerSignal m_rulerSignal;
|
||||
TRulerSpectrum m_rulerSpectrum;
|
||||
};
|
||||
} // namespace AdvancedVisualization
|
||||
} // namespace OpenViBE
|
||||
+58
@@ -0,0 +1,58 @@
|
||||
/*********************************************************************
|
||||
* Software License Agreement (AGPL-3 License)
|
||||
*
|
||||
* OpenViBE Designer
|
||||
* Based on OpenViBE V1.1.0, Copyright (C) Inria, 2006-2015
|
||||
* Copyright (C) Inria, 2015-2017,V1.0
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "../mIRuler.hpp"
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace AdvancedVisualization {
|
||||
template <class T1, class T2, class TCondition>
|
||||
class TRulerConditionalPair : public IRuler
|
||||
{
|
||||
public:
|
||||
|
||||
void setRendererContext(const CRendererContext* ctx) override
|
||||
{
|
||||
IRuler::setRendererContext(ctx);
|
||||
condition.setRendererContext(ctx);
|
||||
first.setRendererContext(ctx);
|
||||
second.setRendererContext(ctx);
|
||||
}
|
||||
|
||||
void setRenderer(const IRenderer* renderer) override
|
||||
{
|
||||
IRuler::setRenderer(renderer);
|
||||
condition.setRenderer(renderer);
|
||||
first.setRenderer(renderer);
|
||||
second.setRenderer(renderer);
|
||||
}
|
||||
|
||||
void render() override { condition() ? first.doRender() : second.doRender(); }
|
||||
void renderLeft(GtkWidget* widget) override { condition() ? first.doRenderLeft(widget) : second.doRenderLeft(widget); }
|
||||
void renderRight(GtkWidget* widget) override { condition() ? first.doRenderRight(widget) : second.doRenderRight(widget); }
|
||||
void renderBottom(GtkWidget* widget) override { condition() ? first.doRenderBottom(widget) : second.doRenderBottom(widget); }
|
||||
|
||||
TCondition condition;
|
||||
T1 first;
|
||||
T2 second;
|
||||
};
|
||||
} // namespace AdvancedVisualization
|
||||
} // namespace OpenViBE
|
||||
+74
@@ -0,0 +1,74 @@
|
||||
/*********************************************************************
|
||||
* Software License Agreement (AGPL-3 License)
|
||||
*
|
||||
* OpenViBE Designer
|
||||
* Based on OpenViBE V1.1.0, Copyright (C) Inria, 2006-2015
|
||||
* Copyright (C) Inria, 2015-2017,V1.0
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "../mIRuler.hpp"
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace AdvancedVisualization {
|
||||
template <class T1, class T2>
|
||||
class TRulerPair : public IRuler
|
||||
{
|
||||
public:
|
||||
|
||||
void setRendererContext(const CRendererContext* ctx) override
|
||||
{
|
||||
IRuler::setRendererContext(ctx);
|
||||
first.setRendererContext(ctx);
|
||||
second.setRendererContext(ctx);
|
||||
}
|
||||
|
||||
void setRenderer(const IRenderer* renderer) override
|
||||
{
|
||||
IRuler::setRenderer(renderer);
|
||||
first.setRenderer(renderer);
|
||||
second.setRenderer(renderer);
|
||||
}
|
||||
|
||||
void render() override
|
||||
{
|
||||
first.doRender();
|
||||
second.doRender();
|
||||
}
|
||||
|
||||
void renderLeft(GtkWidget* widget) override
|
||||
{
|
||||
first.doRenderLeft(widget);
|
||||
second.doRenderLeft(widget);
|
||||
}
|
||||
|
||||
void renderRight(GtkWidget* widget) override
|
||||
{
|
||||
first.doRenderRight(widget);
|
||||
second.doRenderRight(widget);
|
||||
}
|
||||
|
||||
void renderBottom(GtkWidget* widget) override
|
||||
{
|
||||
first.doRenderBottom(widget);
|
||||
second.doRenderBottom(widget);
|
||||
}
|
||||
|
||||
T1 first;
|
||||
T2 second;
|
||||
};
|
||||
} // namespace AdvancedVisualization
|
||||
} // namespace OpenViBE
|
||||
Reference in New Issue
Block a user