This commit is contained in:
2021-10-14 13:47:35 +02:00
commit 6625a8dfaa
4026 changed files with 844291 additions and 0 deletions
@@ -0,0 +1,32 @@
#if defined(TARGET_HAS_ThirdPartyOgre3D)
#include "ovassvepCCommandShipControl.h"
#include "ovassvepCShooterApplication.h"
namespace OpenViBE {
namespace SSVEP {
CCommandShipControl::CCommandShipControl(CShooterApplication* application) : ICommandVRPNButton(application, "SSVEP_VRPN_ShipControl") {}
void CCommandShipControl::execute(const int button, const int /*state*/)
{
CShooterApplication* shooterApplication = dynamic_cast<CShooterApplication*>(m_application);
switch (button)
{
case 0:
shooterApplication->getShip()->shoot();
break;
case 1:
shooterApplication->getShip()->rotate(-6);
break;
case 2:
shooterApplication->getShip()->rotate(6);
break;
default: break;
}
}
} // namespace SSVEP
} // namespace OpenViBE
#endif
@@ -0,0 +1,18 @@
#pragma once
#include "../ovassvepICommandVRPNButton.h"
namespace OpenViBE {
namespace SSVEP {
class CShooterApplication;
class CCommandShipControl final : public ICommandVRPNButton
{
public:
explicit CCommandShipControl(CShooterApplication* application);
~CCommandShipControl() override {}
void execute(const int button, const int state) override;
};
} // namespace SSVEP
} // namespace OpenViBE
@@ -0,0 +1,44 @@
#if defined(TARGET_HAS_ThirdPartyOgre3D)
#include "ovassvepCCommandTargetControl.h"
#include "ovassvepCShooterApplication.h"
namespace OpenViBE {
namespace SSVEP {
CCommandTargetControl::CCommandTargetControl(CShooterApplication* application)
: ICommandVRPNButton(application, "SSVEP_VRPN_ShooterTarget")
{
m_vrpnServer = CVRPNServer::getInstance(application);
m_vrpnServer->addButton("SSVEP_VRPN_TargetRequest", 1);
}
void CCommandTargetControl::processFrame()
{
CShooterApplication* application = dynamic_cast<CShooterApplication*>(m_application);
ICommandVRPNButton::processFrame();
if (application->m_TargetRequest)
{
m_application->getLogManager() << Kernel::LogLevel_Info << "Requesting target\n";
m_vrpnServer->changeButtonState("SSVEP_VRPN_TargetRequest", 0, 1);
application->m_TargetRequest = false;
}
else { m_vrpnServer->changeButtonState("SSVEP_VRPN_TargetRequest", 0, 0); }
m_vrpnServer->processFrame();
}
void CCommandTargetControl::execute(const int button, const int state)
{
if (state == 1)
{
m_application->getLogManager() << Kernel::LogLevel_Info << "Target created at position " << button << "\n";
dynamic_cast<CShooterApplication*>(m_application)->addTarget(button);
}
}
} // namespace SSVEP
} // namespace OpenViBE
#endif
@@ -0,0 +1,23 @@
#pragma once
#include "../ovassvepICommandVRPNButton.h"
#include "../ovassvepCVRPNServer.h"
namespace OpenViBE {
namespace SSVEP {
class CShooterApplication;
class CCommandTargetControl final : public ICommandVRPNButton
{
public:
explicit CCommandTargetControl(CShooterApplication* application);
~CCommandTargetControl() override {}
void execute(const int button, const int state) override;
void processFrame() override;
private:
CVRPNServer* m_vrpnServer = nullptr;
};
} // namespace SSVEP
} // namespace OpenViBE
@@ -0,0 +1,114 @@
#if defined(TARGET_HAS_ThirdPartyOgre3D)
#include "ovassvepCShooterApplication.h"
#include "../ovassvepCCommandStartStop.h"
#include "../ovassvepCCommandStimulatorControl.h"
#include "ovassvepCCommandTargetControl.h"
#include "ovassvepCCommandShipControl.h"
namespace OpenViBE {
namespace SSVEP {
#if !((CEGUI_VERSION_MAJOR > 0) || (CEGUI_VERSION_MINOR >= 8))
namespace CEGUI
{
typedef CEGUI::UVector2 USize;
};
#endif
CShooterApplication::~CShooterApplication()
{
(*m_logManager) << Kernel::LogLevel_Debug << "- m_ship\n";
delete m_ship;
}
bool CShooterApplication::setup(Kernel::IKernelContext* kernelCtx)
{
if (!CApplication::setup(kernelCtx))
{
// If setup failed, logmanager may be in an unusable state, use cout
std::cout << "Error: Base application setup failed\n";
return false;
}
// Create the StarShip object
(*m_logManager) << Kernel::LogLevel_Debug << "+ m_ship = new CStarShip(...)\n";
m_ship = new CStarShip(this, m_sceneNode, 0.3F, &m_oFrequencies);
// Initialize the Target class
CShooterTarget::initialize(m_painter, m_sceneNode);
// draw the initial text
m_instructionsReady = m_guiManager->createWindow("TaharezLook/StaticImage", "InstructionsReady");
m_instructionsReady->setPosition(CEGUI::UVector2(cegui_reldim(0.0F), cegui_reldim(0.0F)));
m_instructionsReady->setSize(CEGUI::USize(CEGUI::UDim(0.0F, 640.F), CEGUI::UDim(0.0F, 32.F)));
#if (CEGUI_VERSION_MAJOR > 0) || (CEGUI_VERSION_MINOR >= 8)
m_sheet->addChild(m_instructionsReady);
CEGUI::ImageManager::getSingleton().addFromImageFile("InstructionsReady", "InstructionText-Start.png");
m_instructionsReady->setProperty("Image", "InstructionsReady");
#else
m_sheet->addChildWindow(m_instructionsReady);
CEGUI::ImagesetManager::getSingleton().createFromImageFile("InstructionsReady", "InstructionText-Start.png");
m_instructionsReady->setProperty("Image", "set:InstructionsReady image:full_image");
#endif
m_instructionsReady->setProperty("FrameEnabled", "False");
m_instructionsReady->setProperty("BackgroundEnabled", "False");
m_instructionsReady->setVisible(true);
// Create commands
(*m_logManager) << Kernel::LogLevel_Debug << "+ addCommand(new CCommandStartStop(...)\n";
this->addCommand(new CCommandStartStop(this));
(*m_logManager) << Kernel::LogLevel_Debug << "+ addCommand(new CCommandStimulatorControl(...))\n";
this->addCommand(new CCommandStimulatorControl(this));
(*m_logManager) << Kernel::LogLevel_Debug << "+ addCommand(new CCommandTargetControl(...)\n";
this->addCommand(new CCommandTargetControl(this));
(*m_logManager) << Kernel::LogLevel_Debug << "+ addCommand(new CCommandShipControl(...))\n";
this->addCommand(new CCommandShipControl(this));
return true;
}
void CShooterApplication::processFrame(const size_t frame)
{
CApplication::processFrame(frame);
m_ship->processFrame(frame);
if (m_ship->isShooting())
{
for (auto it = m_targets.begin(); it != m_targets.end(); ++it)
{
if ((*it)->collidesWith(m_ship->getShotCoordinates()))
{
delete *it;
m_targets.erase(it);
m_TargetRequest = true;
break;
}
}
}
}
void CShooterApplication::addTarget(const size_t targetPosition)
{
m_targets.push_back(CShooterTarget::createTarget(Ogre::Radian(Ogre::Math::PI * 2 / 360 * 45 * targetPosition)));
}
void CShooterApplication::startExperiment()
{
m_TargetRequest = true;
CApplication::startExperiment();
m_instructionsReady->setVisible(false);
}
} // namespace SSVEP
} // namespace OpenViBE
#endif
@@ -0,0 +1,33 @@
#pragma once
#include <openvibe/ov_all.h>
#include <toolkit/ovtk_all.h>
#include "../ovassvepCApplication.h"
#include "ovassvepCShooterTarget.h"
#include "ovassvepCStarShip.h"
namespace OpenViBE {
namespace SSVEP {
class CShooterApplication final : public CApplication
{
public:
CShooterApplication() : CApplication() {}
~CShooterApplication() override;
bool setup(Kernel::IKernelContext* kernelCtx) override;
CStarShip* getShip() const { return m_ship; }
void startExperiment() override;
void addTarget(size_t targetPosition);
bool m_TargetRequest = false;
private:
void processFrame(const size_t frame) override;
CEGUI::Window* m_instructionsReady = nullptr;
CStarShip* m_ship = nullptr;
std::vector<CShooterTarget*> m_targets;
};
} // namespace SSVEP
} // namespace OpenViBE
@@ -0,0 +1,57 @@
#if defined(TARGET_HAS_ThirdPartyOgre3D)
#include "ovassvepCShooterTarget.h"
namespace OpenViBE {
namespace SSVEP {
Ogre::SceneNode* CShooterTarget::m_parentNode = nullptr;
CBasicPainter* CShooterTarget::m_painter = nullptr;
void CShooterTarget::initialize(CBasicPainter* painter, Ogre::SceneNode* parentNode)
{
m_painter = painter;
m_parentNode = parentNode;
}
CShooterTarget* CShooterTarget::createTarget(const Ogre::Radian angle)
{
if (m_painter == nullptr)
{
std::cerr << "The CShooterTarget was not initialized" << std::endl;
return nullptr;
}
return new CShooterTarget(angle);
}
CShooterTarget::CShooterTarget(const Ogre::Radian angle)
{
m_targetNode = m_parentNode->createChildSceneNode();
Ogre::MovableObject* targetObject = m_painter->paintCircle(0.0F, 1.0F - 1.0F * SSVEP_SHOOTER_TARGET_SIZE, SSVEP_SHOOTER_TARGET_SIZE,
Ogre::ColourValue(1.0F, 1.0F, 1.0F));
targetObject->setVisible(true);
m_targetNode->attachObject(targetObject);
m_targetNode->roll(angle);
}
CShooterTarget::~CShooterTarget()
{
m_targetNode->removeAndDestroyAllChildren();
m_targetNode->getCreator()->destroySceneNode(m_targetNode);
}
bool CShooterTarget::collidesWith(const std::pair<Ogre::Real, Ogre::Real> point) const
{
const Ogre::Radian theta = (m_targetNode->getOrientation()).getRoll();
const Ogre::Real targetDist = 1.0F - 2 * SSVEP_SHOOTER_TARGET_SIZE;
const Ogre::Real dist = sqrt(pow(point.first + Ogre::Math::Sin(theta) * targetDist, 2) + pow(point.second - Ogre::Math::Cos(theta) * targetDist, 2));
return dist <= SSVEP_SHOOTER_TARGET_SIZE;
}
} // namespace SSVEP
} // namespace OpenViBE
#endif
@@ -0,0 +1,29 @@
#pragma once
#include <Ogre.h>
#include "../ovassvepCBasicPainter.h"
#define SSVEP_SHOOTER_TARGET_SIZE 0.15f
namespace OpenViBE {
namespace SSVEP {
class CShooterTarget
{
public:
static CShooterTarget* createTarget(Ogre::Radian angle);
static void initialize(CBasicPainter* painter, Ogre::SceneNode* parentNode);
~CShooterTarget();
bool collidesWith(std::pair<Ogre::Real, Ogre::Real> point) const;
private:
static Ogre::SceneNode* m_parentNode;
static CBasicPainter* m_painter;
Ogre::SceneNode* m_targetNode = nullptr;
explicit CShooterTarget(Ogre::Radian angle);
};
} // namespace SSVEP
} // namespace OpenViBE
@@ -0,0 +1,152 @@
#if defined(TARGET_HAS_ThirdPartyOgre3D)
#include "ovassvepCStarShip.h"
#include "../ovassvepCApplication.h"
#include "../ovassvepCSSVEPFlickeringObject.h"
#define SSVEP_SHIP_HULL_COLOUR Ogre::ColourValue(0.0F, 0.5F, 0.5F)
#define SIGN(x) ( (x) < 0 ? -1 : 1 )
namespace OpenViBE {
namespace SSVEP {
CStarShip::CStarShip(CApplication* application, Ogre::SceneNode* parentNode, const Ogre::Real radius, std::vector<std::pair<size_t, size_t>>* frequencies)
{
// get configuration and controlling objects
Kernel::IConfigurationManager* configManager = application->getConfigurationManager();
CBasicPainter* painter = application->getPainter();
m_angularSpeed = Ogre::Real(configManager->expandAsFloat(
"${SSVEP_ShipAngularSpeed}", Ogre::Math::PI / 60.0F));
application->getLogManager() << Kernel::LogLevel_Info << "Ship Angluar Speed : " << m_angularSpeed << "\n";
const Ogre::ColourValue lightColor = Ogre::ColourValue(float(configManager->expandAsFloat("${SSVEP_TargetLightColourRed}", 1.0F)),
float(configManager->expandAsFloat("${SSVEP_TargetLightColourGreen}", 1.0F)),
float(configManager->expandAsFloat("${SSVEP_TargetLightColourBlue}", 1.0F)));
const Ogre::ColourValue darkColor = Ogre::ColourValue(float(configManager->expandAsFloat("${SSVEP_TargetDarkColourRed}", 0.0F)),
float(configManager->expandAsFloat("${SSVEP_TargetDarkColourGreen}", 0.0F)),
float(configManager->expandAsFloat("${SSVEP_TargetDarkColourBlue}", 0.0F)));
// draw the ship scene objects
m_shipNode = parentNode->createChildSceneNode();
m_shotNode = m_shipNode->createChildSceneNode();
Ogre::MovableObject* shipHull = painter->paintCircle(0.0F, 0.0F, radius, SSVEP_SHIP_HULL_COLOUR, false, 2);
m_shipNode->attachObject(shipHull);
shipHull->setVisible(true);
// Ogre::RealRect wingRectangle = { - radius * 0.4f, radius * 0.4f, radius * 0.4f, -radius * 0.4f };
const Ogre::RealRect wingRectangle(-radius * 0.4F, radius * 0.4F, radius * 0.4F, -radius * 0.4F);
// paint the cannon
Ogre::SceneNode* drawnObjectNode = m_shipNode->createChildSceneNode();
Ogre::MovableObject* drawnObject = painter->paintTriangle(Point(0.0F, radius * 0.4F), Point(- radius * 0.4F, -radius * 0.4F),
Point(radius * 0.4F, -radius * 0.4F), lightColor);
drawnObject->setVisible(true);
drawnObjectNode->attachObject(drawnObject);
drawnObject = painter->paintTriangle(Point(0.0F, radius * 0.4F), Point(- radius * 0.4F, -radius * 0.4F), Point(radius * 0.4F, -radius * 0.4F), darkColor);
drawnObject->setVisible(false);
drawnObjectNode->attachObject(drawnObject);
drawnObjectNode->setPosition(0.0, radius, 0.0);
m_shipCannon = new CSSVEPFlickeringObject(drawnObjectNode, (*frequencies)[1].first, (*frequencies)[1].second);
// paint the left wing
drawnObjectNode = m_shipNode->createChildSceneNode();
drawnObject = painter->paintRectangle(wingRectangle, lightColor);
drawnObject->setVisible(true);
drawnObjectNode->attachObject(drawnObject);
drawnObject = painter->paintRectangle(wingRectangle, darkColor);
drawnObject->setVisible(false);
drawnObjectNode->attachObject(drawnObject);
drawnObjectNode->setPosition(-radius * 0.875F, -radius * 0.875F, 0.0);
m_shipLeftWing = new CSSVEPFlickeringObject(drawnObjectNode, (*frequencies)[2].first, (*frequencies)[2].second);
// paint the right wing
drawnObjectNode = m_shipNode->createChildSceneNode();
drawnObject = painter->paintRectangle(wingRectangle, lightColor);
drawnObject->setVisible(true);
drawnObjectNode->attachObject(drawnObject);
drawnObject = painter->paintRectangle(wingRectangle, darkColor);
drawnObject->setVisible(false);
drawnObjectNode->attachObject(drawnObject);
drawnObjectNode->setPosition(radius * 0.875F, -radius * 0.875F, 0.0F);
m_shipRightWing = new CSSVEPFlickeringObject(drawnObjectNode, (*frequencies)[3].first, (*frequencies)[3].second);
// create the shot
drawnObject = painter->paintTriangle(Point(0.0F, radius * 0.25F), Point(-radius * 0.125F, 0.0F), Point(radius * 0.125F, 0.0F),
Ogre::ColourValue(1.0F, 1.0F, 0.0F));
drawnObject->setVisible(false);
m_shotNode->attachObject(drawnObject);
drawnObject = painter->paintTriangle(Point(-radius * 0.125F, 0.0F), Point(0.0F, -radius * 0.75F), Point(radius * 0.125F, 0.0F),
Ogre::ColourValue(1.0F, 1.0F, 0.0F));
drawnObject->setVisible(false);
m_shotNode->attachObject(drawnObject);
}
void CStarShip::processFrame(const size_t /*currentFrame*/)
{
m_shipCannon->processFrame();
m_shipLeftWing->processFrame();
m_shipRightWing->processFrame();
if (m_nCurrentRotation != 0)
{
m_shipNode->roll(Ogre::Radian(m_angularSpeed * SIGN(m_nCurrentRotation)));
m_currentAngle += Ogre::Radian(m_angularSpeed * SIGN(m_nCurrentRotation));
m_nCurrentRotation -= SIGN(m_nCurrentRotation);
}
if (m_isShooting)
{
m_shotDistance += 0.07F;
m_shotNode->setPosition(0.0, m_shotDistance, 0.0);
if (m_shotDistance > 1.5F)
{
m_isShooting = false;
m_shotNode->setVisible(false);
}
}
}
void CStarShip::shoot()
{
if (m_isShooting) { return; }
m_isShooting = true;
m_shotDistance = 0.0F;
m_shotNode->setPosition(0.0F, 0.0F, 0.0F);
m_shotNode->setVisible(true);
}
std::pair<Ogre::Real, Ogre::Real> CStarShip::getShotCoordinates() const
{
return std::make_pair(-Ogre::Math::Sin(m_currentAngle) * m_shotDistance, Ogre::Math::Cos(m_currentAngle) * m_shotDistance);
}
} // namespace SSVEP
} // namespace OpenViBE
#endif
@@ -0,0 +1,39 @@
#pragma once
#include <Ogre.h>
#include <openvibe/ov_all.h>
#include <toolkit/ovtk_all.h>
namespace OpenViBE {
namespace SSVEP {
class CApplication;
class CSSVEPFlickeringObject;
class CStarShip
{
public:
CStarShip(CApplication* application, Ogre::SceneNode* parentNode, Ogre::Real radius, std::vector<std::pair<size_t, size_t>>* frequencies);
void processFrame(const size_t currentFrame);
void rotate(const int nRotation) { m_nCurrentRotation += nRotation; }
bool isShooting() const { return m_isShooting; }
void shoot();
std::pair<Ogre::Real, Ogre::Real> getShotCoordinates() const;
private:
Ogre::SceneNode* m_shipNode = nullptr;
CSSVEPFlickeringObject* m_shipCannon = nullptr;
CSSVEPFlickeringObject* m_shipLeftWing = nullptr;
CSSVEPFlickeringObject* m_shipRightWing = nullptr;
Ogre::Real m_angularSpeed;
Ogre::Radian m_currentAngle;
int m_nCurrentRotation = 0;
Ogre::SceneNode* m_shotNode = nullptr;
bool m_isShooting = false;
Ogre::Real m_shotDistance = 0.0F;
};
} // namespace SSVEP
} // namespace OpenViBE
@@ -0,0 +1,19 @@
#pragma once
#include "../ovassvepICommandVRPNButton.h"
#include "ovassvepCTrainerApplication.h"
namespace OpenViBE {
namespace SSVEP {
class CTrainerApplication;
class CCommandReceiveTarget final : public ICommandVRPNButton
{
public:
explicit CCommandReceiveTarget(CApplication* application) : ICommandVRPNButton(application, "SSVEP_VRPN_Target") {}
~CCommandReceiveTarget() override { }
void execute(const int button, const int state) override { dynamic_cast<CTrainerApplication*>(m_application)->setTarget(button); }
};
} // namespace SSVEP
} // namespace OpenViBE
@@ -0,0 +1,125 @@
#if defined(TARGET_HAS_ThirdPartyOgre3D)
#include "ovassvepCTrainerApplication.h"
#include "../ovassvepCCommandStartStop.h"
#include "../ovassvepCCommandStimulatorControl.h"
#include "ovassvepCCommandReceiveTarget.h"
namespace OpenViBE {
namespace SSVEP {
#if !((CEGUI_VERSION_MAJOR > 0) || (CEGUI_VERSION_MINOR >= 8))
namespace CEGUI
{
typedef CEGUI::UVector2 USize;
};
#endif
bool CTrainerApplication::setup(Kernel::IKernelContext* kernelCtx)
{
if (!CApplication::setup(kernelCtx)) { return false; }
(*m_logManager) << Kernel::LogLevel_Debug << " * CTrainerApplication::setup()\n";
Kernel::IConfigurationManager* configManager = &(m_kernelCtx->getConfigurationManager());
CTrainerFlickeringObject::initialize(this);
// paint targets
const size_t nTarget = size_t(configManager->expandAsUInteger("${SSVEP_TargetCount}"));
for (size_t i = 0; i < nTarget; ++i) { this->addObject(CTrainerFlickeringObject::createTrainerFlickeringObject(i)); }
// draw the initial text
m_instructionsReady = m_guiManager->createWindow("TaharezLook/StaticImage", "InstructionsReady");
m_instructionsReady->setPosition(CEGUI::UVector2(cegui_reldim(0.0F), cegui_reldim(0.0F)));
m_instructionsReady->setSize(CEGUI::USize(CEGUI::UDim(0.0F, 640.F), CEGUI::UDim(0.0F, 32.F)));
#if (CEGUI_VERSION_MAJOR > 0) || (CEGUI_VERSION_MINOR >= 8)
m_sheet->addChild(m_instructionsReady);
CEGUI::ImageManager::getSingleton().addFromImageFile("InstructionsReady", "InstructionText-Start.png");
m_instructionsReady->setProperty("Image", "InstructionsReady");
#else
m_sheet->addChildWindow(m_instructionsReady);
CEGUI::ImagesetManager::getSingleton().createFromImageFile("InstructionsReady", "InstructionText-Start.png");
m_instructionsReady->setProperty("Image", "set:InstructionsReady image:full_image");
#endif
m_instructionsReady->setProperty("FrameEnabled", "False");
m_instructionsReady->setProperty("BackgroundEnabled", "False");
m_instructionsReady->setVisible(true);
// initialize commands
(*m_logManager) << Kernel::LogLevel_Debug << "+ addCommand(new CCommandStartStop(...)\n";
this->addCommand(new CCommandStartStop(this));
(*m_logManager) << Kernel::LogLevel_Debug << "+ addCommand(new CCommandStimulatorControl(...))\n";
this->addCommand(new CCommandStimulatorControl(this));
(*m_logManager) << Kernel::LogLevel_Debug << "+ addCommand(new CC(...))\n";
this->addCommand(new CCommandReceiveTarget(this));
(*m_logManager) << Kernel::LogLevel_Debug << " * CTrainerApplication::setup() completed successfully\n";
return true;
}
void CTrainerApplication::processFrame(const size_t frame)
{
CApplication::processFrame(frame);
if (!m_active) { return; }
for (size_t i = 0; i < m_oObjects.size(); ++i) { m_oObjects[i]->processFrame(); }
}
void CTrainerApplication::addObject(CTrainerFlickeringObject* obj)
{
m_oObjects.push_back(obj);
obj->setVisible(true);
}
void CTrainerApplication::setTarget(const int target)
{
const size_t currentTime = int(time(nullptr) - m_ttStartTime);
(*m_logManager) << Kernel::LogLevel_Info << currentTime << " > Target set to " << target << "\n";
for (int i = 0; i < int(m_oObjects.size()); ++i) { m_oObjects[i]->setTarget(target == i); }
}
void CTrainerApplication::startExperiment()
{
CApplication::startExperiment();
m_ttStartTime = time(nullptr);
this->stopFlickering();
m_instructionsReady->setVisible(false);
}
void CTrainerApplication::startFlickering()
{
const size_t currentTime = size_t(time(nullptr) - m_ttStartTime);
(*m_logManager) << Kernel::LogLevel_Info << currentTime << " > Starting Visual Stimulation\n";
m_active = true;
}
void CTrainerApplication::stopFlickering()
{
const size_t currentTime = size_t(time(nullptr) - m_ttStartTime);
(*m_logManager) << Kernel::LogLevel_Info << currentTime << " > Stopping Visual Stimulation\n";
m_active = false;
for (size_t i = 0; i < m_oObjects.size(); ++i) { m_oObjects[i]->setVisible(true); }
this->setTarget(-1);
}
} // namespace SSVEP
} // namespace OpenViBE
#endif
@@ -0,0 +1,36 @@
#pragma once
#include <CEGUI.h>
#include "../ovassvepCApplication.h"
#include "ovassvepCTrainerFlickeringObject.h"
namespace OpenViBE {
namespace SSVEP {
class CTrainerApplication final : public CApplication
{
public:
CTrainerApplication() : CApplication() {}
~CTrainerApplication() override {}
bool setup(Kernel::IKernelContext* kernelCtx) override;
void setTarget(int target);
void startExperiment() override;
void startFlickering() override;
void stopFlickering() override;
private:
bool m_active = false;
void processFrame(const size_t frame) override;
void addObject(CTrainerFlickeringObject* obj);
std::vector<CTrainerFlickeringObject*> m_oObjects;
time_t m_ttStartTime = 0;
CEGUI::Window* m_instructionsReady = nullptr;
};
} // namespace SSVEP
} // namespace OpenViBE
@@ -0,0 +1,91 @@
#if defined(TARGET_HAS_ThirdPartyOgre3D)
#include "ovassvepCTrainerFlickeringObject.h"
#include "ovassvepCTrainerApplication.h"
namespace OpenViBE {
namespace SSVEP {
Ogre::SceneNode* CTrainerFlickeringObject::m_parentNode = nullptr;
CBasicPainter* CTrainerFlickeringObject::m_painter = nullptr;
Ogre::ColourValue CTrainerFlickeringObject::m_lightColor = Ogre::ColourValue(1.0F, 1.0F, 1.0F);
Ogre::ColourValue CTrainerFlickeringObject::m_darkColor = Ogre::ColourValue(0.0F, 0.0F, 0.0F);
float CTrainerFlickeringObject::m_targetWidth = 0.2F;
float CTrainerFlickeringObject::m_targetHeight = 0.2F;
CTrainerApplication* CTrainerFlickeringObject::m_application = nullptr;
void CTrainerFlickeringObject::initialize(CTrainerApplication* application)
{
m_application = application;
Kernel::IConfigurationManager* configManager = application->getConfigurationManager();
m_painter = application->getPainter();
m_parentNode = application->getSceneNode();
m_targetWidth = float(configManager->expandAsFloat("${SSVEP_TargetWidth}"));
m_targetHeight = float(configManager->expandAsFloat("${SSVEP_TargetHeight}"));
m_lightColor = Ogre::ColourValue(float(configManager->expandAsFloat("${SSVEP_TargetLightColourRed}")),
float(configManager->expandAsFloat("${SSVEP_TargetLightColourGreen}")),
float(configManager->expandAsFloat("${SSVEP_TargetLightColourBlue}")));
m_darkColor = Ogre::ColourValue(float(configManager->expandAsFloat("${SSVEP_TargetDarkColourRed}")),
float(configManager->expandAsFloat("${SSVEP_TargetDarkColourGreen}")),
float(configManager->expandAsFloat("${SSVEP_TargetDarkColourBlue}")));
}
CTrainerFlickeringObject* CTrainerFlickeringObject::createTrainerFlickeringObject(const size_t targetId)
{
Kernel::IConfigurationManager* configManager = m_application->getConfigurationManager();
if (m_painter != nullptr)
{
const Ogre::ColourValue currentTargetColour = (targetId == 0) ? m_darkColor : m_lightColor;
const CIdentifier id = configManager->createConfigurationToken("SSVEPTarget_Id", std::to_string(targetId).c_str());
const float targetX = float(configManager->expandAsFloat("${SSVEP_Target_X_${SSVEPTarget_Id}}"));
const float targetY = float(configManager->expandAsFloat("${SSVEP_Target_Y_${SSVEPTarget_Id}}"));
const size_t framesL = (*(m_application->getFrequencies()))[targetId].first;
const size_t framesD = (*(m_application->getFrequencies()))[targetId].second;
m_application->getLogManager() << Kernel::LogLevel_Info << "New trainer object : id=" << targetId << " litFrames=" << framesL <<
" darkFrames=" << framesD << "\n";
configManager->releaseConfigurationToken(id);
return new CTrainerFlickeringObject(targetX, targetY, currentTargetColour, uint8_t(framesL), uint8_t(framesD));
}
m_application->getLogManager() << Kernel::LogLevel_Fatal << "TrainerTarget object was not properly initialized\n";
return nullptr;
}
CTrainerFlickeringObject::CTrainerFlickeringObject(const float posX, const float posY, const Ogre::ColourValue colour, const uint8_t litFrames,
const uint8_t darkFrames)
: CSSVEPFlickeringObject(nullptr, litFrames, darkFrames)
{
m_elementNode = m_parentNode->createChildSceneNode();
m_objectNode = m_elementNode->createChildSceneNode();
Ogre::SceneNode* pointerNode = m_elementNode->createChildSceneNode();
const Ogre::RealRect rectangle(posX - m_targetWidth / 2, posY + m_targetHeight / 2, posX + m_targetWidth / 2, posY - m_targetHeight / 2);
Ogre::MovableObject* litObject = m_painter->paintRectangle(rectangle, colour);
m_objectNode->attachObject(litObject);
litObject->setVisible(true);
Ogre::MovableObject* darkObject = m_painter->paintRectangle(rectangle, m_darkColor);
m_objectNode->attachObject(darkObject);
darkObject->setVisible(false);
m_pointer = m_painter->paintTriangle(Point(posX - 0.05F, posY + m_targetHeight), Point(posX, posY + m_targetHeight - 0.05F),
Point(posX + 0.05F, posY + m_targetHeight), Ogre::ColourValue(1, 1, 0));
pointerNode->attachObject(m_pointer);
m_pointer->setVisible(false);
}
} // namespace SSVEP
} // namespace OpenViBE
#endif
@@ -0,0 +1,40 @@
#pragma once
#include <openvibe/ov_all.h>
#include <toolkit/ovtk_all.h>
#include <Ogre.h>
#include "../ovassvepCSSVEPFlickeringObject.h"
#include "../ovassvepCBasicPainter.h"
namespace OpenViBE {
namespace SSVEP {
class CTrainerApplication;
class CTrainerFlickeringObject final : public CSSVEPFlickeringObject
{
public:
static CTrainerFlickeringObject* createTrainerFlickeringObject(size_t targetId);
static void initialize(CTrainerApplication* application);
static void connectToNode(Ogre::SceneNode* /*sceneNode*/) { }
void setTarget(const bool isTarget) const { m_pointer->setVisible(isTarget); }
bool isTarget() const { return m_pointer->getVisible(); }
private:
static CTrainerApplication* m_application;
static Ogre::SceneNode* m_parentNode;
static CBasicPainter* m_painter;
static float m_targetWidth;
static float m_targetHeight;
static Ogre::ColourValue m_lightColor;
static Ogre::ColourValue m_darkColor;
CTrainerFlickeringObject(float posX, float posY, Ogre::ColourValue colour, uint8_t litFrames, uint8_t darkFrames);
Ogre::SceneNode* m_elementNode = nullptr;
Ogre::MovableObject* m_pointer = nullptr;
};
} // namespace SSVEP
} // namespace OpenViBE
@@ -0,0 +1,286 @@
#if defined(TARGET_HAS_ThirdPartyOgre3D)
#include "ovassvepCApplication.h"
#include <cmath>
#include "fs/Files.h"
namespace OpenViBE {
namespace SSVEP {
#define MIN(a,b) ( (a) < (b) ? (a) : (b) )
//---------------------------------------------------------------------------------------------------
CApplication::~CApplication()
{
if (m_painter != nullptr)
{
(*m_logManager) << Kernel::LogLevel_Debug << "- m_painter\n";
delete m_painter;
m_painter = nullptr;
}
for (auto it = m_oCommands.begin();
it != m_oCommands.end(); ++it)
{
(*m_logManager) << Kernel::LogLevel_Debug << "- ICommand\n";
if (*it != nullptr)
{
delete *it;
*it = nullptr;
}
}
(*m_logManager) << Kernel::LogLevel_Debug << "- m_root\n";
if (m_root != nullptr)
{
delete m_root;
m_root = nullptr;
}
}
//---------------------------------------------------------------------------------------------------
bool CApplication::setup(Kernel::IKernelContext* poKernelContext)
{
m_kernelCtx = poKernelContext;
m_logManager = &(m_kernelCtx->getLogManager());
Kernel::IConfigurationManager* configurationManager = &(m_kernelCtx->getConfigurationManager());
(*m_logManager) << Kernel::LogLevel_Debug << " * CApplication::setup()\n";
// Plugin config path setup
const CString pluginsPath = configurationManager->expand("${Kernel_3DVisualizationOgrePlugins}");
// Create LogManager to stop Ogre flooding the console and creating random files
(*m_logManager) << Kernel::LogLevel_Info << "Ogre plugins path is " << pluginsPath << "\n";
(*m_logManager) << Kernel::LogLevel_Debug << "+ Creating Ogre logmanager\n";
Ogre::LogManager* logManager = new Ogre::LogManager();
(*m_logManager) << Kernel::LogLevel_Info << "Ogre log to console : " << configurationManager->expandAsBoolean("${SSVEP_Ogre_LogToConsole}", false)
<< "\n";
const CString ogreLog = configurationManager->expand("${Path_Log}") + "/openvibe-ssvep-demo-ogre.log";
(*m_logManager) << Kernel::LogLevel_Info << "Ogre log file : " << ogreLog << "\n";
FS::Files::createParentPath(ogreLog);
logManager->createLog(ogreLog.toASCIIString(), true, configurationManager->expandAsBoolean("${SSVEP_Ogre_LogToConsole}", false), false);
// Root creation
const CString ogreCfg = configurationManager->expand("${Path_UserData}") + "/openvibe-ssvep-demo-ogre.cfg";
(*m_logManager) << Kernel::LogLevel_Debug << "+ m_root = new Ogre::Root(...)\n";
(*m_logManager) << Kernel::LogLevel_Info << "Ogre cfg file : " << ogreCfg << "\n";
m_root = new Ogre::Root(pluginsPath.toASCIIString(), ogreCfg.toASCIIString(), ogreLog.toASCIIString());
// Resource handling
setupResources();
// Configuration from file or dialog window if needed
if (!configure())
{
(*m_logManager) << Kernel::LogLevel_Fatal << "The configuration process ended unexpectedly.\n";
return false;
}
// m_window = m_root->initialise(true);
Ogre::NameValuePairList optionList;
m_root->initialise(false);
optionList["vsync"] = "1";
m_window = m_root->createRenderWindow("SSVEP Stimulator", 640, 480, configurationManager->expandAsBoolean("${SSVEP_Ogre_FullScreen}", false), &optionList);
m_windowWidth = m_window->getWidth();
m_windowHeight = m_window->getHeight();
m_sceneManager = m_root->createSceneManager(Ogre::ST_GENERIC);
m_camera = m_sceneManager->createCamera("SSVEPApplicationCamera");
Ogre::SceneManager* fillSceneManager = m_root->createSceneManager(Ogre::ST_GENERIC);
Ogre::Camera* fillCamera = fillSceneManager->createCamera("SSVEPFillCamera");
m_window->addViewport(fillCamera, 0);
m_viewport = m_window->addViewport(m_camera, 1);
this->resizeViewport();
// m_viewport->setBackgroundColour(Ogre::ColourValue(0.0, 0.5, 0.5));
m_camera->setAspectRatio(Ogre::Real(m_viewport->getActualWidth()) / Ogre::Real(m_viewport->getActualHeight()));
m_sceneNode = m_sceneManager->getRootSceneNode()->createChildSceneNode("SSVEPApplicationNode");
// initialize the painter object
(*m_logManager) << Kernel::LogLevel_Debug << "+ m_painter = new CBasicPainter(...)\n";
m_painter = new CBasicPainter(this);
(*m_logManager) << Kernel::LogLevel_Debug << " * initializing CEGUI\n";
this->initCEGUI(configurationManager->expand("${Path_Log}") + "/openvibe-ssvep-demo-cegui.log");
(*m_logManager) << Kernel::LogLevel_Debug << " * CEGUI initialized\n";
// create the vector of stimulation frequencies
m_ScreenRefreshRate = double(configurationManager->expandAsUInteger("${SSVEP_ScreenRefreshRate}"));
(*m_logManager) << Kernel::LogLevel_Info << "Specified screen refresh rate :" << m_ScreenRefreshRate << "Hz\n";
size_t i = 1;
CIdentifier frequencyId = configurationManager->createConfigurationToken("SSVEP_FrequencyId", "1");
m_oFrequencies.push_back(std::pair<size_t, size_t>(30, 30));
while (configurationManager->lookUpConfigurationTokenIdentifier(configurationManager->expand("SSVEP_Frequency_${SSVEP_FrequencyId}"))
!= CIdentifier::undefined())
{
std::pair<size_t, size_t> frequency;
double currentFrequency;
currentFrequency = double(configurationManager->expandAsFloat("${SSVEP_Frequency_${SSVEP_FrequencyId}}"));
const double approximatedFrameCount = m_ScreenRefreshRate / currentFrequency;
if (fabs(approximatedFrameCount - floor(approximatedFrameCount + 0.5)) < 0.003)
{
frequency.first = int(floor(approximatedFrameCount + 0.5)) / 2 + int(floor(approximatedFrameCount + 0.5)) % 2;
frequency.second = int(floor(approximatedFrameCount + 0.5)) / 2;
(*m_logManager) << Kernel::LogLevel_Info << "Frequency number " << i << ": " << currentFrequency << "Hz / " << floor(approximatedFrameCount + 0.5)
<< " ( " << frequency.first << ", " << frequency.second << ") frames @ " << m_ScreenRefreshRate << "fps\n";
m_oFrequencies.push_back(frequency);
}
else { (*m_logManager) << Kernel::LogLevel_Error << "The selected frequency (" << currentFrequency << "Hz) is not supported by your screen.\n"; }
configurationManager->releaseConfigurationToken(frequencyId);
frequencyId = configurationManager->createConfigurationToken("SSVEP_FrequencyId", std::to_string(++i).c_str());
}
return true;
}
//---------------------------------------------------------------------------------------------------
bool CApplication::configure() const
{
if (! m_root->restoreConfig())
{
if (! m_root->showConfigDialog())
{
(*m_logManager) << Kernel::LogLevel_Error << "No configuration created from the dialog window.\n";
return false;
}
}
// Set hard-coded parameters, VSync in particular
m_root->getRenderSystem()->setConfigOption("VSync", "True");
// m_root->getRenderSystem()->setConfigOption("Full Screen", "Yes");
m_root->getRenderSystem()->setConfigOption("Video Mode", "640 x 480 @ 16-bit colour");
return true;
}
//---------------------------------------------------------------------------------------------------
void CApplication::initCEGUI(const char* logFilename)
{
// Instantiate logger before bootstrapping the system, this way we will be able to get the log redirected
if (!CEGUI::Logger::getSingletonPtr()) { new CEGUI::DefaultLogger(); } // singleton; instantiate only, no delete
(*m_logManager) << Kernel::LogLevel_Info << "+ CEGUI log will be in '" << logFilename << "'\n";
FS::Files::createParentPath(logFilename);
CEGUI::Logger::getSingleton().setLogFilename(logFilename, false);
(*m_logManager) << Kernel::LogLevel_Debug << "+ Creating CEGUI Ogre bootstrap\n";
m_roGUIRenderer = &(CEGUI::OgreRenderer::bootstrapSystem(*m_window));
(*m_logManager) << Kernel::LogLevel_Debug << "+ Creating CEGUI Scheme Manager\n";
#if (CEGUI_VERSION_MAJOR > 0) || (CEGUI_VERSION_MINOR >= 8)
CEGUI::SchemeManager::getSingleton().createFromFile(const_cast<CEGUI::utf8*>(reinterpret_cast<const CEGUI::utf8*>("TaharezLook-ov-0.8.scheme")));
#else
CEGUI::SchemeManager::getSingleton().create(reinterpret_cast<CEGUI::utf8*>("TaharezLook-ov.scheme"));
#endif
(*m_logManager) << Kernel::LogLevel_Debug << "+ Creating CEGUI WindowManager\n";
m_guiManager = CEGUI::WindowManager::getSingletonPtr();
m_sheet = m_guiManager->createWindow("DefaultWindow", "Sheet");
(*m_logManager) << Kernel::LogLevel_Debug << "+ Setting CEGUI StyleSheet\n";
#if (CEGUI_VERSION_MAJOR > 0) || (CEGUI_VERSION_MINOR >= 8)
CEGUI::System::getSingleton().getDefaultGUIContext().setRootWindow(m_sheet);
#else
CEGUI::System::getSingleton().setGUISheet(m_sheet);
#endif
}
//---------------------------------------------------------------------------------------------------
void CApplication::resizeViewport()
{
(*m_logManager) << Kernel::LogLevel_Trace << "Creating a new viewport\n";
const Ogre::uint32 size = MIN(m_windowWidth, m_windowHeight);
(*m_logManager) << Kernel::LogLevel_Info << "New viewport size : " << size << "\n";
m_viewport->setDimensions(Ogre::Real(m_windowWidth - size) / Ogre::Real(m_windowWidth) / 2,
Ogre::Real(m_windowHeight - size) / Ogre::Real(m_windowHeight) / 2,
Ogre::Real(size) / Ogre::Real(m_windowWidth), Ogre::Real(size) / Ogre::Real(m_windowHeight));
}
//---------------------------------------------------------------------------------------------------
void CApplication::processFrame(const size_t /*currentFrame*/)
{
if (m_windowWidth != m_window->getWidth() || m_windowHeight != m_window->getHeight())
{
m_windowWidth = m_window->getWidth();
m_windowHeight = m_window->getHeight();
this->resizeViewport();
}
}
//---------------------------------------------------------------------------------------------------
void CApplication::setupResources()
{
Ogre::ResourceGroupManager::getSingleton().createResourceGroup("SSVEP");
Ogre::ResourceGroupManager::getSingleton().addResourceLocation((Directories::getDataDir() + "/applications/ssvep-demo/resources").toASCIIString(),
"FileSystem", "SSVEP");
Ogre::ResourceGroupManager::getSingleton().addResourceLocation((Directories::getDataDir() + "/applications/ssvep-demo/resources/trainer").toASCIIString(),
"FileSystem", "SSVEPTrainer");
Ogre::ResourceGroupManager::getSingleton().addResourceLocation((Directories::getDataDir() + "/applications/ssvep-demo/resources/gui").toASCIIString(),
"FileSystem", "CEGUI");
Ogre::ResourceGroupManager::getSingleton().initialiseResourceGroup("SSVEP");
Ogre::ResourceGroupManager::getSingleton().initialiseResourceGroup("SSVEPTrainer");
Ogre::ResourceGroupManager::getSingleton().initialiseResourceGroup("CEGUI");
}
//---------------------------------------------------------------------------------------------------
bool CApplication::frameStarted(const Ogre::FrameEvent& /*evt*/)
{
++m_currFrame;
m_currFrame = m_currFrame % int(m_ScreenRefreshRate);
this->processFrame(m_currFrame);
for (size_t i = 0; i < m_oCommands.size(); ++i) { m_oCommands[i]->processFrame(); }
return true;
}
//---------------------------------------------------------------------------------------------------
void CApplication::go()
{
(*m_logManager) << Kernel::LogLevel_Debug << "Associating application as Ogre frame listener\n";
m_root->addFrameListener(this);
(*m_logManager) << Kernel::LogLevel_Debug << "Entering Ogre rendering loop\n";
m_root->startRendering();
(*m_logManager) << Kernel::LogLevel_Debug << "Ogre rendering loop finished ... exiting\n";
}
//---------------------------------------------------------------------------------------------------
void CApplication::stopExperiment()
{
(*m_logManager) << Kernel::LogLevel_Info << "[!] Experiment halting\n";
this->exit();
}
} // namespace SSVEP
} // namespace OpenViBE
#endif // TARGET_HAS_ThirdPartyOgre3D
@@ -0,0 +1,87 @@
#pragma once
#include "ovassvep_defines.h"
#include <openvibe/ov_all.h>
#include <toolkit/ovtk_all.h>
#include <Ogre.h>
#include <vector>
#include <CEGUI.h>
#if (CEGUI_VERSION_MAJOR > 0) || (CEGUI_VERSION_MINOR >= 8)
#include <CEGUI/RendererModules/Ogre/Renderer.h>
#else
#include <RendererModules/Ogre/CEGUIOgreRenderer.h>
#endif
#include "ovassvepICommand.h"
#include "ovassvepCBasicPainter.h"
namespace OpenViBE {
namespace SSVEP {
class CApplication : public Ogre::FrameListener, public Ogre::WindowEventListener
{
public:
CApplication() {}
~CApplication() override;
void addCommand(ICommand* command) { m_oCommands.push_back(command); }
virtual bool setup(Kernel::IKernelContext* poKernelContext);
void go();
virtual void startExperiment() { (*m_logManager) << Kernel::LogLevel_Info << "[!] Experiment starting\n"; }
virtual void stopExperiment();
virtual void startFlickering() {}
virtual void stopFlickering() {}
Ogre::RenderWindow* getWindow() const { return m_window; }
Ogre::SceneManager* getSceneManager() const { return m_sceneManager; }
Ogre::SceneNode* getSceneNode() const { return m_sceneNode; }
CBasicPainter* getPainter() const { return m_painter; }
void exit() { m_bContinueRendering = false; }
Kernel::ILogManager& getLogManager() const { return (*m_logManager); }
Kernel::IConfigurationManager* getConfigurationManager() const { return &(m_kernelCtx->getConfigurationManager()); }
std::vector<std::pair<size_t, size_t>>* getFrequencies() { return &m_oFrequencies; }
void resizeViewport();
protected:
Kernel::IKernelContext* m_kernelCtx = nullptr;
Kernel::ILogManager* m_logManager = nullptr;
double m_ScreenRefreshRate = 0;
CBasicPainter* m_painter = nullptr;
bool m_bContinueRendering = true;
size_t m_currFrame = 0;
Ogre::Root* m_root = nullptr;
Ogre::SceneManager* m_sceneManager = nullptr;
Ogre::Camera* m_camera = nullptr;
Ogre::RenderWindow* m_window = nullptr;
Ogre::Viewport* m_viewport = nullptr;
Ogre::SceneNode* m_sceneNode = nullptr;
CEGUI::OgreRenderer* m_roGUIRenderer = nullptr;
CEGUI::WindowManager* m_guiManager = nullptr;
CEGUI::Window* m_sheet = nullptr;
std::vector<std::pair<size_t, size_t>> m_oFrequencies;
std::vector<ICommand*> m_oCommands;
virtual void processFrame(const size_t currentFrame);
bool frameRenderingQueued(const Ogre::FrameEvent& evt) override { return (m_bContinueRendering && !m_window->isClosed()); }
bool frameStarted(const Ogre::FrameEvent& evt) override;
bool configure() const;
static void setupResources();
private:
void initCEGUI(const char* logFilename);
Ogre::uint32 m_windowWidth = 0;
Ogre::uint32 m_windowHeight = 0;
};
} // namespace SSVEP
} // namespace OpenViBE
@@ -0,0 +1,162 @@
#if defined(TARGET_HAS_ThirdPartyOgre3D)
#include "ovassvepCBasicPainter.h"
#include "ovassvepCApplication.h"
#if (OGRE_VERSION_MAJOR > 1) || ((OGRE_VERSION_MAJOR == 1) && (OGRE_VERSION_MINOR >= 9))
#include "Overlay/OgreOverlayManager.h"
#include "Overlay/OgreOverlaySystem.h"
#endif
namespace OpenViBE {
namespace SSVEP {
//---------------------------------------------------------------------------------------------------
CBasicPainter::CBasicPainter(CApplication* application)
: m_application(application), m_sceneManager(application->getSceneManager())
{
m_aabInf.setInfinite();
#if (OGRE_VERSION_MAJOR > 1) || ((OGRE_VERSION_MAJOR == 1) && (OGRE_VERSION_MINOR >= 9))
// on Ogre 1.9, overlay system needs to be manually created
Ogre::OverlaySystem* pOverlaySystem = OGRE_NEW Ogre::OverlaySystem();
m_sceneManager->addRenderQueueListener(pOverlaySystem);
#endif
m_overlayManager = Ogre::OverlayManager::getSingletonPtr();
(m_application->getLogManager()) << Kernel::LogLevel_Debug << " + Creating OverlayManager\n";
Ogre::Overlay* overlay = m_overlayManager->create("TextOverlay");
m_overlayContainer = dynamic_cast<Ogre::OverlayContainer*>(m_overlayManager->createOverlayElement("Panel", "TextContainer"));
m_overlayContainer->setDimensions(1, 1);
m_overlayContainer->setPosition(0, 0);
overlay->add2D(m_overlayContainer);
overlay->show();
}
//---------------------------------------------------------------------------------------------------
Ogre::ManualObject* CBasicPainter::paintRectangle(const Ogre::RealRect& oRectangle, const Ogre::ColourValue color, const int plane) const
{
Ogre::ManualObject* object = m_sceneManager->createManualObject();
object->begin("BasicSurface/Diffuse", Ogre::RenderOperation::OT_TRIANGLE_FAN);
object->setUseIdentityProjection(true);
object->setUseIdentityView(true);
object->position(oRectangle.right, oRectangle.top, 0.0);
object->colour(color);
object->index(0);
object->position(oRectangle.left, oRectangle.top, 0.0);
object->colour(color);
object->index(1);
object->position(oRectangle.left, oRectangle.bottom, 0.0);
object->colour(color);
object->index(2);
object->position(oRectangle.right, oRectangle.bottom, 0.0);
object->colour(color);
object->index(3);
object->index(0);
object->end();
object->setBoundingBox(m_aabInf);
object->setRenderQueueGroup(Ogre::RENDER_QUEUE_OVERLAY - plane);
object->setVisible(true);
return object;
}
//---------------------------------------------------------------------------------------------------
Ogre::ManualObject* CBasicPainter::paintTriangle(const Point p1, const Point p2, const Point p3, const Ogre::ColourValue color, const int plane) const
{
Ogre::ManualObject* object = m_sceneManager->createManualObject();
object->begin("BasicSurface/Diffuse", Ogre::RenderOperation::OT_TRIANGLE_FAN);
object->setUseIdentityProjection(true);
object->setUseIdentityView(true);
object->position(p1.m_X, p1.m_Y, 0.0);
object->colour(color);
object->index(0);
object->position(p2.m_X, p2.m_Y, 0.0);
object->colour(color);
object->index(1);
object->position(p3.m_X, p3.m_Y, 0.0);
object->colour(color);
object->index(2);
object->index(0);
object->end();
object->setBoundingBox(m_aabInf);
object->setRenderQueueGroup(Ogre::RENDER_QUEUE_OVERLAY - plane);
object->setVisible(true);
return object;
}
//---------------------------------------------------------------------------------------------------
Ogre::ManualObject* CBasicPainter::paintCircle(const Ogre::Real rX, const Ogre::Real rY, const Ogre::Real rR, const Ogre::ColourValue color,
const bool bFilled, const int plane) const
{
Ogre::ManualObject* object = m_sceneManager->createManualObject();
if (bFilled) { object->begin("BasicSurface/Diffuse", Ogre::RenderOperation::OT_TRIANGLE_FAN); }
else { object->begin("BasicSurface/Diffuse", Ogre::RenderOperation::OT_LINE_STRIP); }
object->setUseIdentityProjection(true);
object->setUseIdentityView(true);
float const fAccuracy = 16;
unsigned uiIndex = 0;
for (float theta = 0; theta <= 2 * Ogre::Math::PI; theta += Ogre::Math::PI / fAccuracy)
{
object->position(rX + rR * cos(theta), rY + rR * sin(theta), 0);
object->colour(color);
object->index(uiIndex++);
}
object->index(0);
object->end();
object->setBoundingBox(m_aabInf);
object->setRenderQueueGroup(Ogre::RENDER_QUEUE_OVERLAY - plane);
object->setVisible(true);
return object;
}
//---------------------------------------------------------------------------------------------------
void CBasicPainter::paintText(const std::string& sID, const std::string& sText, const Ogre::Real rX, const Ogre::Real rY,
const Ogre::Real rWidth, const Ogre::Real rHeight, const Ogre::ColourValue& color) const
{
Ogre::OverlayElement* text = m_overlayManager->createOverlayElement("TextArea", sID);
text->setDimensions(rWidth, rHeight);
text->setMetricsMode(Ogre::GMM_PIXELS);
text->setPosition(rX, rY);
text->setParameter("font_name", "DejaVu");
text->setColour(color);
text->setCaption(sText);
m_overlayContainer->addChild(text);
}
#endif
} // namespace SSVEP
} // namespace OpenViBE
@@ -0,0 +1,47 @@
#pragma once
#include <Ogre.h>
#if (OGRE_VERSION_MAJOR > 1) || ((OGRE_VERSION_MAJOR == 1) && (OGRE_VERSION_MINOR >= 9))
#include "Overlay/OgreOverlayContainer.h"
#endif
#define SSVEP_DEFAULT_COLOUR Ogre::ColourValue(1.0f, 1.0f, 1.0f)
namespace OpenViBE {
namespace SSVEP {
class CApplication;
class Point
{
public:
Point(const float x, const float y) : m_X(x), m_Y(y) {}
float m_X = 0.0F, m_Y = 0.0F;
};
class CBasicPainter
{
public:
explicit CBasicPainter(CApplication* application);
~CBasicPainter() {}
Ogre::ManualObject* paintRectangle(const Ogre::RealRect& oRectangle, const Ogre::ColourValue color = SSVEP_DEFAULT_COLOUR, const int plane = 1) const;
Ogre::ManualObject* paintTriangle(const Point p1, const Point p2, const Point p3, const Ogre::ColourValue color = SSVEP_DEFAULT_COLOUR,
const int plane = 1) const;
Ogre::ManualObject* paintCircle(const Ogre::Real rX, const Ogre::Real rY, const Ogre::Real rR, const Ogre::ColourValue color = SSVEP_DEFAULT_COLOUR,
const bool bFilled = true,
const int plane = 1) const;
void paintText(const std::string& sID, const std::string& sText, const Ogre::Real rX, const Ogre::Real rY,
const Ogre::Real rWidth, const Ogre::Real rHeight, const Ogre::ColourValue& color) const;
protected:
CApplication* m_application = nullptr;
Ogre::OverlayManager* m_overlayManager = nullptr;
Ogre::OverlayContainer* m_overlayContainer = nullptr;
Ogre::SceneManager* m_sceneManager = nullptr;
Ogre::AxisAlignedBox m_aabInf;
};
} // namespace SSVEP
} // namespace OpenViBE
@@ -0,0 +1,54 @@
#if defined(TARGET_HAS_ThirdPartyOgre3D)
#include "ovassvepCCommandStartStop.h"
#include "ovassvepCApplication.h"
#include "ovassvepCVRPNServer.h"
namespace OpenViBE {
namespace SSVEP {
//---------------------------------------------------------------------------------------------------
CCommandStartStop::CCommandStartStop(CApplication* application)
: ICommandOIS(application)
{
m_vrpnServer = CVRPNServer::getInstance(application);
m_vrpnServer->addButton("SSVEP_VRPN_StartStop", 2);
}
//---------------------------------------------------------------------------------------------------
CCommandStartStop::~CCommandStartStop()
{
m_application->getLogManager() << Kernel::LogLevel_Info << "End message sent\n";
m_vrpnServer->changeButtonState("SSVEP_VRPN_StartStop", 1, 1);
m_vrpnServer->processFrame();
}
//---------------------------------------------------------------------------------------------------
void CCommandStartStop::processFrame()
{
ICommandOIS::processFrame();
m_vrpnServer->processFrame();
}
//---------------------------------------------------------------------------------------------------
void CCommandStartStop::receiveKeyPressedEvent(const OIS::KeyCode key)
{
if (key == OIS::KC_SPACE)
{
m_application->getLogManager() << Kernel::LogLevel_Info << "Start message sent\n";
m_vrpnServer->changeButtonState("SSVEP_VRPN_StartStop", 0, 1);
}
if (key == OIS::KC_ESCAPE) { m_application->exit(); }
}
//---------------------------------------------------------------------------------------------------
void CCommandStartStop::receiveKeyReleasedEvent(const OIS::KeyCode key)
{
if (key == OIS::KC_SPACE) { m_vrpnServer->changeButtonState("SSVEP_VRPN_StartStop", 0, 0); }
}
} // namespace SSVEP
} // namespace OpenViBE
#endif
@@ -0,0 +1,24 @@
#pragma once
#include "ovassvepICommandOIS.h"
namespace OpenViBE {
namespace SSVEP {
class CVRPNServer;
class CCommandStartStop final : public ICommandOIS
{
public:
explicit CCommandStartStop(CApplication* application);
~CCommandStartStop() override;
void processFrame() override;
void receiveKeyPressedEvent(OIS::KeyCode key) override;
void receiveKeyReleasedEvent(OIS::KeyCode key) override;
private:
CVRPNServer* m_vrpnServer = nullptr;
};
} // namespace SSVEP
} // namespace OpenViBE
@@ -0,0 +1,43 @@
#if defined(TARGET_HAS_ThirdPartyOgre3D)
#include "ovassvepCCommandStimulatorControl.h"
#include "ovassvepCApplication.h"
namespace OpenViBE {
namespace SSVEP {
//---------------------------------------------------------------------------------------------------
CCommandStimulatorControl::CCommandStimulatorControl(CApplication* application)
: ICommandVRPNButton(application, "SSVEP_VRPN_StimulatorControl") {}
//---------------------------------------------------------------------------------------------------
void CCommandStimulatorControl::execute(const int button, const int /*state*/)
{
// only run the commands once, skip
switch (button)
{
case 0:
m_application->startExperiment();
break;
case 1:
m_application->stopExperiment();
break;
case 2:
m_application->startFlickering();
break;
case 3:
m_application->stopFlickering();
break;
default:
m_application->getLogManager() << Kernel::LogLevel_Error << "[ERROR] Unknown command\n";
break;
}
}
} // namespace SSVEP
} // namespace OpenViBE
#endif
@@ -0,0 +1,16 @@
#pragma once
#include "ovassvepICommandVRPNButton.h"
namespace OpenViBE {
namespace SSVEP {
class CCommandStimulatorControl final : public ICommandVRPNButton
{
public:
explicit CCommandStimulatorControl(CApplication* application);
~CCommandStimulatorControl() override { }
void execute(const int button, const int state) override;
};
} // namespace SSVEP
} // namespace OpenViBE
@@ -0,0 +1,26 @@
#if defined(TARGET_HAS_ThirdPartyOgre3D)
#include "ovassvepCSSVEPFlickeringObject.h"
namespace OpenViBE {
namespace SSVEP {
void CSSVEPFlickeringObject::setVisible(const bool visibility)
{
if ((!m_visible && visibility) || (m_visible && !visibility)) { m_objectNode->flipVisibility(); }
m_visible = visibility;
}
void CSSVEPFlickeringObject::processFrame()
{
if (m_currentFrame < m_litFrames) { this->setVisible(true); }
else { this->setVisible(false); }
m_currentFrame++;
if (m_currentFrame == m_litFrames + m_darkFrames) { m_currentFrame = 0; }
}
} // namespace SSVEP
} // namespace OpenViBE
#endif
@@ -0,0 +1,30 @@
#pragma once
#include <openvibe/ov_all.h>
#include <toolkit/ovtk_all.h>
#include <Ogre.h>
namespace OpenViBE {
namespace SSVEP {
class CSSVEPFlickeringObject
{
public:
CSSVEPFlickeringObject(Ogre::SceneNode* objectNode, size_t litFrames, size_t darkFrames)
: m_objectNode(objectNode), m_litFrames(litFrames), m_darkFrames(darkFrames) {}
virtual ~CSSVEPFlickeringObject() {}
virtual void setVisible(bool visibility);
virtual void processFrame();
protected:
Ogre::SceneNode* m_objectNode = nullptr;
size_t m_currentFrame = 0;
size_t m_litFrames = 0;
size_t m_darkFrames = 0;
private:
bool m_visible = true;
};
} // namespace SSVEP
} // namespace OpenViBE
@@ -0,0 +1,53 @@
#if defined(TARGET_HAS_ThirdPartyOgre3D)
#include "ovassvepCVRPNServer.h"
#include "ovassvepCApplication.h"
#include <vrpn_Connection.h>
#include <vrpn_Button.h>
namespace OpenViBE {
namespace SSVEP {
CVRPNServer* CVRPNServer::m_vrpnServerInstance = nullptr;
CApplication* CVRPNServer::m_application = nullptr;
CVRPNServer::CVRPNServer(CApplication* application)
{
m_application = application;
const int port = int(m_application->getConfigurationManager()->expandAsInteger("${VRPN_ExternalServerPort}"));
m_application->getLogManager() << Kernel::LogLevel_Debug << "VRPN SERVER PORT :" << port << "\n";
m_connection = vrpn_create_server_connection(port);
}
CVRPNServer* CVRPNServer::getInstance(CApplication* application)
{
if (m_vrpnServerInstance == nullptr) { m_vrpnServerInstance = new CVRPNServer(application); }
return m_vrpnServerInstance;
}
void CVRPNServer::addButton(const CString& name, const int buttonCount)
{
m_buttonServer.insert(
std::pair<std::string, vrpn_Button_Server*>(name.toASCIIString(), new vrpn_Button_Server(name.toASCIIString(), m_connection, buttonCount)));
m_buttonCache[name.toASCIIString()].clear();
m_buttonCache[name.toASCIIString()].resize(buttonCount);
}
void CVRPNServer::processFrame()
{
for (auto& it : m_buttonServer) { it.second->mainloop(); }
m_connection->mainloop();
}
void CVRPNServer::changeButtonState(const std::string& name, const int index, const int state)
{
m_buttonServer[name]->set_button(index, state);
m_buttonCache[name][index] = state;
}
} // namespace SSVEP
} // namespace OpenViBE
#endif
@@ -0,0 +1,39 @@
#pragma once
#include <openvibe/ov_all.h>
#include <toolkit/ovtk_all.h>
#include <map>
#include <vector>
#include <string>
class vrpn_Connection;
class vrpn_Button_Server;
namespace OpenViBE {
namespace SSVEP {
class CApplication;
class CVRPNServer
{
public:
static CVRPNServer* getInstance(CApplication* application);
~CVRPNServer() = default;
void processFrame();
void addButton(const CString& name, int buttonCount);
void changeButtonState(const std::string& name, int index, int state);
int getButtonState(const std::string& name, const int index) { return m_buttonCache[name][index]; }
private:
static CVRPNServer* m_vrpnServerInstance;
static CApplication* m_application;
explicit CVRPNServer(CApplication* application);
vrpn_Connection* m_connection = nullptr;
std::map<std::string, vrpn_Button_Server*> m_buttonServer;
std::map<std::string, std::vector<int>> m_buttonCache;
};
} // namespace SSVEP
} // namespace OpenViBE
@@ -0,0 +1,21 @@
#pragma once
#include <openvibe/ov_all.h>
#include <toolkit/ovtk_all.h>
namespace OpenViBE {
namespace SSVEP {
class CApplication;
class ICommand
{
public:
explicit ICommand(CApplication* application) : m_application(application) {}
virtual ~ICommand() { }
virtual void processFrame() = 0;
protected:
CApplication* m_application = nullptr;
};
} // namespace SSVEP
} // namespace OpenViBE
@@ -0,0 +1,77 @@
#if defined(TARGET_HAS_ThirdPartyOgre3D)
#include "ovassvepICommandOIS.h"
#include "ovassvepCApplication.h"
namespace OpenViBE {
namespace SSVEP {
OIS::InputManager* ICommandOIS::m_inputManager = nullptr;
OIS::Keyboard* ICommandOIS::m_keyboard = nullptr;
int ICommandOIS::m_nInstance = 0;
std::vector<ICommandOIS*> ICommandOIS::m_instances;
ICommandOIS::ICommandOIS(CApplication* application) : ICommand(application)
{
if (m_keyboard == nullptr)
{
OIS::ParamList paramList;
std::ostringstream windowHandleString;
size_t windowHandle;
m_application->getWindow()->getCustomAttribute("WINDOW", &windowHandle);
windowHandleString << windowHandle;
paramList.insert(std::make_pair(std::string("WINDOW"), windowHandleString.str()));
paramList.insert(std::make_pair(std::string("x11_keyboard_grab"), "false"));
m_inputManager = OIS::InputManager::createInputSystem(paramList);
m_keyboard = dynamic_cast<OIS::Keyboard*>(m_inputManager->createInputObject(OIS::OISKeyboard, true));
m_keyboard->setEventCallback(this);
}
m_nInstance++;
m_instances.push_back(this);
}
ICommandOIS::~ICommandOIS()
{
--m_nInstance;
if (m_nInstance == 0)
{
if (m_inputManager != nullptr)
{
if (m_keyboard != nullptr)
{
m_application->getLogManager() << Kernel::LogLevel_Debug << "- destroy m_keyboard\n";
m_inputManager->destroyInputObject(m_keyboard);
m_keyboard = nullptr;
}
m_inputManager->destroyInputSystem(m_inputManager);
}
}
}
bool ICommandOIS::keyPressed(const OIS::KeyEvent& event)
{
for (size_t i = 0; i < m_instances.size(); ++i) { m_instances[i]->receiveKeyPressedEvent(event.key); }
return true;
}
bool ICommandOIS::keyReleased(const OIS::KeyEvent& event)
{
for (size_t i = 0; i < m_instances.size(); ++i) { m_instances[i]->receiveKeyReleasedEvent(event.key); }
return true;
}
} // namespace SSVEP
} // namespace OpenViBE
#endif
@@ -0,0 +1,35 @@
#pragma once
#include <vector>
#include <OIS.h>
#include <OISKeyboard.h>
#include "ovassvepICommand.h"
namespace OpenViBE {
namespace SSVEP {
class ICommandOIS : public ICommand, OIS::KeyListener
{
static std::vector<ICommandOIS*> m_instances;
static int m_nInstance;
protected:
static OIS::InputManager* m_inputManager;
static OIS::Keyboard* m_keyboard;
public:
explicit ICommandOIS(CApplication* application);
~ICommandOIS() override;
void processFrame() override { m_keyboard->capture(); }
protected:
virtual void receiveKeyPressedEvent(OIS::KeyCode key) = 0;
virtual void receiveKeyReleasedEvent(OIS::KeyCode key) = 0;
private:
bool keyPressed(const OIS::KeyEvent& event) override;
bool keyReleased(const OIS::KeyEvent& event) override;
};
} // namespace SSVEP
} // namespace OpenViBE
@@ -0,0 +1,39 @@
#if defined(TARGET_HAS_ThirdPartyOgre3D)
#include "ovassvepICommandVRPNButton.h"
#include "ovassvepCApplication.h"
#include <vrpn_Connection.h>
#include <vrpn_Button.h>
namespace OpenViBE {
namespace SSVEP {
static void VRPN_CALLBACK ssvep_vrpn_callback_button(void* command, const vrpn_BUTTONCB button)
{
static_cast<ICommandVRPNButton*>(command)->execute(button.button, button.state);
}
ICommandVRPNButton::ICommandVRPNButton(CApplication* application, const CString& name)
: ICommand(application)
{
Kernel::IConfigurationManager* configManager = application->getConfigurationManager();
const std::string buttonName = std::string(name.toASCIIString()) + "@" + (configManager->expand("${SSVEP_VRPNHost}")).toASCIIString();
m_application->getLogManager() << Kernel::LogLevel_Debug << "+ m_vrpnButton = new vrpn_Button_Remote(" << buttonName << ")\n";
m_vrpnButton = new vrpn_Button_Remote(buttonName.c_str());
m_vrpnButton->register_change_handler(static_cast<void*>(this), ssvep_vrpn_callback_button);
}
ICommandVRPNButton::~ICommandVRPNButton()
{
m_application->getLogManager() << Kernel::LogLevel_Debug << "- delete m_vrpnButton\n";
delete m_vrpnButton;
}
void ICommandVRPNButton::processFrame() { m_vrpnButton->mainloop(); }
} // namespace SSVEP
} // namespace OpenViBE
#endif
@@ -0,0 +1,22 @@
#pragma once
#include "ovassvepICommand.h"
class vrpn_Button_Remote;
namespace OpenViBE {
namespace SSVEP {
class ICommandVRPNButton : public ICommand
{
public:
ICommandVRPNButton(CApplication* application, const CString& name);
~ICommandVRPNButton() override;
void processFrame() override;
virtual void execute(const int button, const int state) = 0;
protected:
vrpn_Button_Remote* m_vrpnButton = nullptr;
};
} // namespace SSVEP
} // namespace OpenViBE
@@ -0,0 +1,126 @@
#if defined(TARGET_HAS_ThirdPartyOgre3D)
#include "ovassvep_defines.h"
#include <openvibe/ov_all.h>
#include <toolkit/ovtk_all.h>
#include "ovassvepCApplication.h"
#include "Trainer/ovassvepCTrainerApplication.h"
#include "Shooter/ovassvepCShooterApplication.h"
int main(const int argc, char** argv)
{
if (argc != 2)
{
std::cout << "Usage: " << argv[0] << " [trainer|shooter]\n";
exit(1);
}
// initialize the OpenViBE kernel
OpenViBE::CKernelLoader kernelLoader;
OpenViBE::Kernel::IKernelDesc* kernelDesc = nullptr;
OpenViBE::CString error;
#if defined TARGET_OS_Windows
const OpenViBE::CString kernelFile = OpenViBE::Directories::getLibDir() + "/openvibe-kernel.dll";
#else
const OpenViBE::CString kernelFile = OpenViBE::Directories::getLibDir() + "/libopenvibe-kernel.so";
#endif
if (!kernelLoader.load(kernelFile, &error))
{
std::cout << "[ FAILED ] Error loading kernel (" << error << ")" << " from [" << kernelFile << "]\n";
return (1);
}
std::cout << "[ INF ] Kernel module loaded, trying to get kernel descriptor\n";
kernelLoader.initialize();
kernelLoader.getKernelDesc(kernelDesc);
if (!kernelDesc)
{
std::cout << "[ FAILED ] No kernel descriptor\n";
return (1);
}
std::cout << "[ INF ] Got kernel descriptor, trying to create kernel\n";
OpenViBE::Kernel::IKernelContext* kernelContext = kernelDesc->createKernel("ssvep-demo", OpenViBE::Directories::getDataDir() + "/kernel/openvibe.conf");
if (!kernelContext)
{
std::cout << "[ FAILED ] No kernel created by kernel descriptor\n";
return (1);
}
kernelContext->initialize();
OpenViBE::Toolkit::initialize(*kernelContext);
OpenViBE::Kernel::IConfigurationManager* configManager = &(kernelContext->getConfigurationManager());
configManager->createConfigurationToken("SSVEP_ApplicationDescriptor", OpenViBE::CString(argv[1]));
const OpenViBE::CString configFile = configManager->expand("${Path_Data}/applications/ssvep-demo/openvibe-ssvep-demo.conf");
configManager->addConfigurationFromFile(configFile);
OpenViBE::Kernel::ILogManager* logManager = &(kernelContext->getLogManager());
if (configManager->expand("$Env{OGRE_HOME}").length() == 0)
{
std::cout << "Error: OGRE_HOME environment variable is not set, this likely will not work.\n";
// Don't exit as we don't have any way to get the return value seen in designer
}
// We need this to address BuildType no longer in SDK 2.0
#if defined(DEBUG)
configManager->addOrReplaceConfigurationToken("BuildType", "Debug");
#else
configManager->addOrReplaceConfigurationToken("BuildType", "Release");
#endif
OpenViBE::SSVEP::CApplication* app;
const OpenViBE::CString applicationType = configManager->expand("${SSVEP_ApplicationType}");
(*logManager) << OpenViBE::Kernel::LogLevel_Info << "Selected Application : '" << applicationType.toASCIIString() << "'\n";
if (applicationType == OpenViBE::CString("trainer"))
{
(*logManager) << OpenViBE::Kernel::LogLevel_Debug << "+ app = new SSVEP::CTrainerApplication(...)\n";
app = new OpenViBE::SSVEP::CTrainerApplication();
}
else if (applicationType == OpenViBE::CString("shooter"))
{
(*logManager) << OpenViBE::Kernel::LogLevel_Debug << "+ app = new SSVEP::CShooterApplication(...)\n";
app = new OpenViBE::SSVEP::CShooterApplication();
}
else
{
(*logManager) << OpenViBE::Kernel::LogLevel_Error << "Wrong application identifier specified: '" << applicationType << "'\n";
return 1;
}
if (!app->setup(kernelContext))
{
std::cout << "Aborting\n";
delete app;
return -1;
}
app->go();
(*logManager) << OpenViBE::Kernel::LogLevel_Debug << "- app\n";
delete app;
return 0;
}
#else
#include <stdio.h>
int main(int argc, char** argv)
{
std::cout << "SSVEP demo has not been compiled as it depends on Ogre (missing/disabled)\n";
return -1;
}
#endif