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,134 @@
#if defined(TARGET_HAS_ThirdPartyOgre3DTerrain)
#include "ovamsCGenericStimulatorApplication.h"
#include "../log/ovkCLogListenerFileBuffered.h"
#include "../ovamsCCommandStartStop.h"
#include "../ovamsCCommandStimulatorControl.h"
#include "../ovamsCCommandReceiveTarget.h"
namespace OpenViBE {
namespace SSVEPMindShooter {
#if !((CEGUI_VERSION_MAJOR > 0) || (CEGUI_VERSION_MINOR >= 8))
namespace CEGUI
{
typedef CEGUI::UVector2 USize;
};
#endif
bool CGenericStimulatorApplication::setup(Kernel::IKernelContext* poKernelContext)
{
CApplication::setup(poKernelContext);
(*m_logManager) << Kernel::LogLevel_Debug << " * CGenericStimulatorApplication::setup()\n";
Kernel::IConfigurationManager* configManager = &(m_kernelCtx->getConfigurationManager());
configManager->addConfigurationFromFile(m_ScenarioDir + "/appconf/generic-configuration.conf");
std::cout << m_ScenarioDir << "/appconf/generic-configuration.conf" << "\n";
poKernelContext->getLogManager().activate(Kernel::LogLevel_First, Kernel::LogLevel_Last, true);
Kernel::ILogListener* logListenerFileBuffered = new Kernel::CLogListenerFileBuffered(*poKernelContext, "ssvep-stimulator",
configManager->expand(
"${SSVEP_UserDataFolder}/log-[$core{date}-$core{time}].log"));
poKernelContext->getLogManager().addListener(logListenerFileBuffered);
CGenericStimulatorFlickeringObject::initialize(this);
// paint targets
const size_t nTarget = size_t(configManager->expandAsUInteger("${SSVEP_TargetCount}"));
for (size_t i = 0; i < nTarget; ++i) { this->addObject(CGenericStimulatorFlickeringObject::createGenericFlickeringObject(i)); }
// draw the initial text
m_instructionsReady = m_guiWindowManager->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 CGenericStimulatorApplication::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 CGenericStimulatorApplication::addObject(CGenericStimulatorFlickeringObject* obj)
{
m_oObjects.push_back(obj);
obj->setVisible(true);
}
void CGenericStimulatorApplication::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 CGenericStimulatorApplication::startExperiment()
{
CApplication::startExperiment();
m_ttStartTime = time(nullptr);
this->stopFlickering();
m_instructionsReady->setVisible(false);
}
void CGenericStimulatorApplication::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 CGenericStimulatorApplication::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 SSVEPMindShooter
} // namespace OpenViBE
#endif
@@ -0,0 +1,36 @@
#pragma once
#include <CEGUI.h>
#include "../ovamsCApplication.h"
#include "ovamsCGenericStimulatorFlickeringObject.h"
namespace OpenViBE {
namespace SSVEPMindShooter {
class CGenericStimulatorApplication final : public CApplication
{
public:
explicit CGenericStimulatorApplication(const CString& sScenarioDir) : CApplication(sScenarioDir) {}
~CGenericStimulatorApplication() override {}
bool setup(Kernel::IKernelContext* poKernelContext) override;
void setTarget(int target) override;
void startExperiment() override;
void startFlickering() override;
void stopFlickering() override;
private:
bool m_active = false;
void processFrame(const size_t frame) override;
void addObject(CGenericStimulatorFlickeringObject* obj);
std::vector<CGenericStimulatorFlickeringObject*> m_oObjects;
time_t m_ttStartTime = 0;
CEGUI::Window* m_instructionsReady = nullptr;
};
} // namespace SSVEPMindShooter
} // namespace OpenViBE
@@ -0,0 +1,105 @@
#if defined(TARGET_HAS_ThirdPartyOgre3DTerrain)
#include "ovamsCGenericStimulatorFlickeringObject.h"
#include "ovamsCGenericStimulatorApplication.h"
namespace OpenViBE {
namespace SSVEPMindShooter {
Ogre::SceneNode* CGenericStimulatorFlickeringObject::m_parentNode = nullptr;
CBasicPainter* CGenericStimulatorFlickeringObject::m_painter = nullptr;
Ogre::ColourValue CGenericStimulatorFlickeringObject::m_lightColor = Ogre::ColourValue(1.0F, 1.0F, 1.0F);
Ogre::ColourValue CGenericStimulatorFlickeringObject::m_darkColor = Ogre::ColourValue(0.0F, 0.0F, 0.0F);
float CGenericStimulatorFlickeringObject::m_targetWidth = 0.2F;
float CGenericStimulatorFlickeringObject::m_targetHeight = 0.2F;
CGenericStimulatorApplication* CGenericStimulatorFlickeringObject::m_application = nullptr;
void CGenericStimulatorFlickeringObject::initialize(CGenericStimulatorApplication* 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}")));
m_application->getLogManager() << Kernel::LogLevel_Info << "Target Size : (" << m_targetWidth << ", " << m_targetHeight << ")\n";
//m_application->getLogManager() << Kernel::LogLevel_Info << "Target Default Colour : Light = " << Ogre::String(m_lightColor) << ", Dark = " << Ogre::String(m_darkColor) << "\n";
}
CGenericStimulatorFlickeringObject* CGenericStimulatorFlickeringObject::createGenericFlickeringObject(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 CString material = CString(configManager->expand("${SSVEP_Target_Material_${SSVEPTarget_Id}}"));
const size_t stimulationPattern = size_t((*(m_application->getFrequencies()))[targetId]);
m_application->getLogManager() << Kernel::LogLevel_Info << "Target (" << targetId << ") : Position = ("
<< targetX << ", " << targetY << "), Texture = " << material << "\n";
configManager->releaseConfigurationToken(id);
return new CGenericStimulatorFlickeringObject(targetX, targetY, currentTargetColour, material, stimulationPattern);
}
m_application->getLogManager() << Kernel::LogLevel_Fatal << "TrainerTarget object was not properly initialized\n";
return nullptr;
}
CGenericStimulatorFlickeringObject::CGenericStimulatorFlickeringObject(const float posX, const float posY, const Ogre::ColourValue color,
const CString& material, const size_t stimulationPattern)
: CSSVEPFlickeringObject(nullptr, stimulationPattern)
{
Ogre::MovableObject* litObject;
Ogre::MovableObject* darkObject;
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);
if (strcmp(material.toASCIIString(), "default") == 0)
{
litObject = m_painter->paintRectangle(rectangle, color);
darkObject = m_painter->paintRectangle(rectangle, m_darkColor);
}
else
{
litObject = m_painter->paintTexturedRectangle(rectangle, std::string("GenericSurface/").append(material));
darkObject = m_painter->paintTexturedRectangle(rectangle, std::string("GenericSurface/").append(material).append("-dark"));
}
m_objectNode->attachObject(litObject);
litObject->setVisible(true);
m_objectNode->attachObject(darkObject);
darkObject->setVisible(false);
m_pointer = m_painter->paintTriangle(Ogre::Vector2(posX - 0.05F, posY + m_targetHeight), Ogre::Vector2(posX, posY + m_targetHeight - 0.05F),
Ogre::Vector2(posX + 0.05F, posY + m_targetHeight), Ogre::ColourValue(1, 1, 0));
pointerNode->attachObject(m_pointer);
m_pointer->setVisible(false);
}
} // namespace SSVEPMindShooter
} // namespace OpenViBE
#endif
@@ -0,0 +1,40 @@
#pragma once
#include <openvibe/ov_all.h>
#include <toolkit/ovtk_all.h>
#include <Ogre.h>
#include "../ovamsCSSVEPFlickeringObject.h"
#include "../ovamsCBasicPainter.h"
namespace OpenViBE {
namespace SSVEPMindShooter {
class CGenericStimulatorApplication;
class CGenericStimulatorFlickeringObject final : public CSSVEPFlickeringObject
{
public:
static CGenericStimulatorFlickeringObject* createGenericFlickeringObject(size_t targetId);
static void initialize(CGenericStimulatorApplication* 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 CGenericStimulatorApplication* 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;
CGenericStimulatorFlickeringObject(float posX, float posY, Ogre::ColourValue color, const CString& material, size_t stimulationPattern);
Ogre::SceneNode* m_elementNode = nullptr;
Ogre::MovableObject* m_pointer = nullptr;
};
} // namespace SSVEPMindShooter
} // namespace OpenViBE
@@ -0,0 +1,130 @@
/*
* @author Ogre
* @note This code likely originates from the Ogre project
*
*/
#pragma once
// Includes
#include <OgreVector3.h>
#include <OgreQuaternion.h>
#include <vector>
#include "rapidxml.hpp"
// Forward declarations
namespace Ogre {
class SceneManager;
class SceneNode;
class TerrainGroup;
class TerrainGlobalOptions;
}
/*
namespace Forests
{
class PagedGeometry;
class TreeLoader3D;
class GrassLoader;
class GrassLayer;
}
*/
class nodeProperty
{
public:
Ogre::String m_NodeName;
Ogre::String m_PropertyName;
Ogre::String m_ValueName;
Ogre::String m_TypeName;
nodeProperty(const Ogre::String& node, const Ogre::String& propertyName, const Ogre::String& value, const Ogre::String& type)
: m_NodeName(node), m_PropertyName(propertyName), m_ValueName(value), m_TypeName(type) {}
};
class DotSceneLoader
{
public:
Ogre::TerrainGlobalOptions* m_TerrainGlobalOptions = nullptr;
DotSceneLoader();
virtual ~DotSceneLoader();
void parseDotScene(const Ogre::String& sceneName, const Ogre::String& groupName, Ogre::SceneManager* yourSceneMgr,
Ogre::SceneNode* pAttachNode = nullptr, const Ogre::String& prependNode = "");
Ogre::String getProperty(const Ogre::String& ndNm, const Ogre::String& prop);
Ogre::String getResourceLocationBaseDir() const { return m_resLocationsBaseDir; }
void setResourceLocationBaseDir(const Ogre::String& newBaseDir) { m_resLocationsBaseDir = newBaseDir; }
// Ogre::TerrainGroup* getTerrainGroup() { return mTerrainGroup; }
std::vector<nodeProperty> m_NodeProperties;
std::vector<Ogre::String> m_StaticObjects;
std::vector<Ogre::String> m_DynamicObjects;
// std::vector<Forests::PagedGeometry *> mPGHandles;
// std::vector<Forests::TreeLoader3D *> mTreeHandles;
// Forests::GrassLoader* mGrassLoaderHandle; // Handle to Forests::GrassLoader object
std::vector<Ogre::ParticleSystem*> m_ParticleSystemList; // contains all the Particle Systems created
protected:
void processScene(rapidxml::xml_node<>* xmlRoot);
void processNodes(rapidxml::xml_node<>* xmlNode);
//! @todo Implement this
static void processExternals(rapidxml::xml_node<>* /*xmlNode*/) { }
void processEnvironment(rapidxml::xml_node<>* xmlNode) const;
void processResourceLocations(rapidxml::xml_node<>* xmlNode) const;
// void processTerrain(rapidxml::xml_node<>* xmlNode);
// void processTerrainPage(rapidxml::xml_node<>* xmlNode);
// void processGrassLayers(rapidxml::xml_node<>* xmlNode);
// void processBlendmaps(rapidxml::xml_node<>* xmlNode);
static void processUserDataReference(rapidxml::xml_node<>* xmlNode, Ogre::SceneNode* pParent = nullptr);
static void processUserDataReference(rapidxml::xml_node<>* xmlNode, Ogre::Entity* pEntity);
static void processOctree(rapidxml::xml_node<>* xmlNode);
void processLight(rapidxml::xml_node<>* xmlNode, Ogre::SceneNode* parent = nullptr);
void processCamera(rapidxml::xml_node<>* xmlNode, Ogre::SceneNode* pParent = nullptr) const;
void processNode(rapidxml::xml_node<>* xmlNode, Ogre::SceneNode* pParent = nullptr);
void processLookTarget(rapidxml::xml_node<>* xmlNode, Ogre::SceneNode* parent) const;
void processTrackTarget(rapidxml::xml_node<>* xmlNode, Ogre::SceneNode* pParent) const;
void processEntity(rapidxml::xml_node<>* xmlNode, Ogre::SceneNode* pParent);
static void processSubEntity(rapidxml::xml_node<>* xmlNode, Ogre::Entity* pEntity);
void processParticleSystem(rapidxml::xml_node<>* xmlNode, Ogre::SceneNode* pParent);
static void processBillboardSet(rapidxml::xml_node<>* xmlNode, Ogre::SceneNode* pParent);
void processPlane(rapidxml::xml_node<>* xmlNode, Ogre::SceneNode* pParent) const;
// void processPagedGeometry(rapidxml::xml_node<>* xmlNode, Ogre::SceneNode *pParent);
void processFog(rapidxml::xml_node<>* xmlNode) const;
void processSkyBox(rapidxml::xml_node<>* xmlNode) const;
void processSkyDome(rapidxml::xml_node<>* xmlNode) const;
void processSkyPlane(rapidxml::xml_node<>* xmlNode) const;
static void processClipping(rapidxml::xml_node<>* xmlNode);
static void processLightRange(rapidxml::xml_node<>* xmlNode, Ogre::Light* pLight);
static void processLightAttenuation(rapidxml::xml_node<>* xmlNode, Ogre::Light* pLight);
static Ogre::String getAttrib(rapidxml::xml_node<>* xmlNode, const Ogre::String& attrib, const Ogre::String& defaultValue = "");
static Ogre::Real getAttribReal(rapidxml::xml_node<>* xmlNode, const Ogre::String& attrib, Ogre::Real defaultValue = 0);
static bool getAttribBool(rapidxml::xml_node<>* xmlNode, const Ogre::String& attrib, bool defaultValue = false);
static Ogre::Vector3 parseVector3(rapidxml::xml_node<>* xmlNode);
static Ogre::Quaternion parseQuaternion(rapidxml::xml_node<>* xmlNode);
static Ogre::ColourValue parseColour(rapidxml::xml_node<>* xmlNode);
Ogre::SceneManager* m_sceneMgr = nullptr;
Ogre::SceneNode* m_attachNode = nullptr;
Ogre::String m_groupName;
Ogre::String m_prependNode;
// Ogre::TerrainGroup* mTerrainGroup = nullptr;
Ogre::Vector3 m_terrainPosition;
Ogre::Vector3 m_lightDirection;
// paged geometry related values
// int mPGPageSize = 0;
// int mPGDetailDistance = 0;
// resource locations basedir
Ogre::String m_resLocationsBaseDir;
};
@@ -0,0 +1,202 @@
#if defined(TARGET_HAS_ThirdPartyOgre3DTerrain)
#include "ovamsCCommandControlAnalog.h"
#include "ovamsCImpactApplication.h"
#include <CEGUI.h>
#if !((CEGUI_VERSION_MAJOR > 0) || (CEGUI_VERSION_MINOR >= 8))
namespace CEGUI
{
typedef CEGUI::UVector2 USize;
};
#endif
namespace OpenViBE {
namespace SSVEPMindShooter {
CCommandControlAnalog::CCommandControlAnalog(CImpactApplication* application, const bool takeControl)
: ICommandVRPNAnalog(application, "SSVEP_VRPN_AnalogControl"), m_application(application), m_inControl(takeControl)
{
m_cmdStates[0] = 0;
m_cmdStates[1] = 0;
m_cmdStates[2] = 0;
m_maxFeedbackLevel[0] = 0;
m_maxFeedbackLevel[1] = 0;
m_maxFeedbackLevel[2] = 0;
}
void CCommandControlAnalog::execute(const int channelCount, double* channel)
{
CImpactApplication* application = dynamic_cast<CImpactApplication*>(m_application);
if (m_inControl)
{
if (channelCount == 4)
{
// 'Modern' multiclass Mind Shooter assumed
// The input class coding is assumed to contain the following probabilities,
// 0 == 'focus on the middle of the ship')
// 1 == focus tip
// 2 == focus left
// 3 == focus right
const std::array<double, 4> probs = { channel[0], channel[1], channel[2], channel[3] };
commandeerShip(probs);
}
else if (channelCount == 6)
{
// 'Classic' Mind Shooter. The input class probabilities are assumed as follows [class1in,class1Out,class2In,class2Out,class3In,class3Out]
// Note that with this control scheme, class 0 will never be selected.
std::array<double, 4> probs = { 0, channel[0], channel[2], channel[4] };
const double sum = probs[1] + probs[2] + probs[3];
if (sum > 0)
{
probs[1] = probs[1] / sum;
probs[2] = probs[2] / sum;
probs[3] = probs[3] / sum;
}
commandeerShip(probs);
}
else
{
application->getLogManager() << Kernel::LogLevel_Error << "Incorrect analog VRPN input with " << channelCount
<< " channels. Mind Shooter needs 4 or 6 channels.\n";
return;
}
}
const int nChannels = 3;
static std::array<int, nChannels> prevLevels = { 0, 0, 0 };
// Assume input is layered like [prob1,prob2,prob3,prob4]. First ignored for feedback (focus middle of ship).
std::array<double, nChannels> feedback = { channel[1], channel[2], channel[3] };
std::array<int, nChannels> level = { 0, 0, 0 };
//std::cout << "feedback: ";
for (int i = 0; i < nChannels; ++i)
{
if (feedback[i] < 0)
{
// Note: shouldn't happen, we're expecting positive numbers
feedback[i] = 0;
}
if (feedback[i] > m_maxFeedbackLevel[i]) { m_maxFeedbackLevel[i] += 0.1; }
else
{
// Slowly decrease max over time in case it was due to artifact
m_maxFeedbackLevel[i] *= 0.995;
}
const double cLevel = (m_maxFeedbackLevel[i] > 0 ? (feedback[i] / m_maxFeedbackLevel[i]) : 0);
if (cLevel > 0.7) { level[i] = 3; }
else if (cLevel > 0.3) { level[i] = 2; }
else if (cLevel > 0.0) { level[i] = 1; }
}
if (level[0] != prevLevels[0] || level[1] != prevLevels[1] || level[2] != prevLevels[2])
{
application->getLogManager() << Kernel::LogLevel_Trace << "Feedback levels : " << level[0] << " " << level[1] << " " << level[2] << "\n";
prevLevels[0] = level[0];
prevLevels[1] = level[1];
prevLevels[2] = level[2];
application->getShip()->setFeedbackLevels(level[0], level[1], level[2]);
}
}
std::string stateToString(const CImpactShip::ETargetState ts)
{
if (ts == CImpactShip::TS_NORMAL) { return "N"; }
if (ts == CImpactShip::TS_INHIBITED) { return "I"; }
if (ts == CImpactShip::TS_OFF) { return "X"; }
return "-";
}
// Expects 4 non-negative inputs
void CCommandControlAnalog::commandeerShip(const std::array<double, 4>& probs)
{
m_cmdStates[0] = 0;
m_cmdStates[1] = 0;
m_cmdStates[2] = 0;
// If true, a NOP classification (class 0) will never be selected
// const bool ignoreIdle = false;
// Find the strongest activation.
size_t maxIdx = 0;
double maxVal = -std::numeric_limits<double>::max();
//double sum = 0;
for (size_t i = 0; i < 4; ++i)
{
if (probs[i] >= maxVal)
// && !(i==0 && ignoreIdle))
{
maxVal = probs[i];
maxIdx = i;
}
//sum += probs[i];
}
//if (sum <= 0) { sum = 1; }
/*
const bool paralyzed = false;
if (l_bParalyzed)
{
// In this mode, the ship does not move but the prediction is displayed instead. May be useful for debugging.
char text[512];
sprintf(text, "Button %d", maxIdx);
double pos = (maxIdx / 3.0) * 0.85;
m_application->getInstructionWindow()->setSize(CEGUI::USize(CEGUI::UDim(0.10f, 0), CEGUI::UDim(0.10f, 0)));
m_application->getInstructionWindow()->setPosition(CEGUI::UVector2(CEGUI::UDim(pos, 0), CEGUI::UDim(0.5f, 0)));
m_application->getInstructionWindow()->setText(text);
m_application->getInstructionWindow()->show();
return;
}
*/
// In principle here we could do different things with the probabilities. If we predict just the
// maximum, this can be expected to be identical to the Classifier Processor box label output,
// hence no difference is expected between the two control schemes (discrete vs analog).
// To make the two controls a bit different, the probabilities can be used to
// modulate the strength of the ship movement.
// Modulating with the probabilities makes the movements a bit jittery
// const double strength = maxVal / sum;
// This choice is smoother, but will make the behavior identical to discrete control
const double strength = 1.0;
CImpactShip* ship = m_application->getShip();
if (maxIdx == NOTHING) { } // NOP
else if (maxIdx == SHOOT && m_application->getShip()->getTargetState(0) != CImpactShip::TS_OFF)
{
m_cmdStates[0] = 1;
ship->shoot();
}
else if (maxIdx == MOVE_LEFT && m_application->getShip()->getTargetState(1) != CImpactShip::TS_OFF)
{
m_cmdStates[1] = 1;
ship->move(int(-6 * strength));
}
else if (maxIdx == MOVE_RIGHT && m_application->getShip()->getTargetState(2) != CImpactShip::TS_OFF)
{
m_cmdStates[2] = 1;
ship->move(int(6 * strength));
}
}
} // namespace SSVEPMindShooter
} // namespace OpenViBE
#endif
@@ -0,0 +1,33 @@
/// Controls the ship movement by the continuous values from the classifier probabilities
// If bTakeControl is false, feedback levels will still be provided by the analog control.
#pragma once
#include "../ovamsICommandVRPNAnalog.h"
#include <array>
namespace OpenViBE {
namespace SSVEPMindShooter {
class CImpactApplication;
class CCommandControlAnalog final : public ICommandVRPNAnalog
{
enum EShipCommand { NOTHING = 0, SHOOT, MOVE_LEFT, MOVE_RIGHT };
public:
CCommandControlAnalog(CImpactApplication* application, bool takeControl);
~CCommandControlAnalog() override {}
void execute(int channelCount, double* channel) override;
private:
CImpactApplication* m_application = nullptr;
std::array<int, 3> m_cmdStates;
std::array<double, 3> m_maxFeedbackLevel;
void commandeerShip(const std::array<double, 4>& probs);
bool m_inControl = false;
};
} // namespace SSVEPMindShooter
} // namespace OpenViBE
@@ -0,0 +1,48 @@
#if defined(TARGET_HAS_ThirdPartyOgre3DTerrain)
#include "ovamsCCommandControlDiscrete.h"
#include "ovamsCImpactApplication.h"
#include <CEGUI.h>
#if !((CEGUI_VERSION_MAJOR > 0) || (CEGUI_VERSION_MINOR >= 8))
namespace CEGUI
{
typedef CEGUI::UVector2 USize;
};
#endif
namespace OpenViBE {
namespace SSVEPMindShooter {
CCommandControlDiscrete::CCommandControlDiscrete(CImpactApplication* application, const bool takeControl)
: ICommandVRPNButton(application, "SSVEP_VRPN_DiscreteControl"), m_inControl(takeControl) {}
void CCommandControlDiscrete::execute(const int button, const int /*state*/)
{
if (!m_inControl) { return; }
CImpactApplication* application = dynamic_cast<CImpactApplication*>(m_application);
switch (button)
{
case 0:
// Nop
break;
case 1:
application->getShip()->shoot();
break;
case 2:
application->getShip()->move(-6);
break;
case 3:
application->getShip()->move(6);
break;
default:
m_application->getLogManager() << Kernel::LogLevel_Warning << "Unhandled button " << button << " received\n";
break;
}
}
} // namespace SSVEPMindShooter
} // namespace OpenViBE
#endif
@@ -0,0 +1,23 @@
/// Control ship movements with VRPN using label predictions from the classifier
// If bTakeControl is false, the class will do nothing.
#pragma once
#include "../ovamsICommandVRPNButton.h"
namespace OpenViBE {
namespace SSVEPMindShooter {
class CImpactApplication;
class CCommandControlDiscrete final : public ICommandVRPNButton
{
public:
CCommandControlDiscrete(CImpactApplication* application, bool takeControl);
~CCommandControlDiscrete() override {}
void execute(const int button, const int state) override;
protected:
bool m_inControl = false;
};
} // namespace SSVEPMindShooter
} // namespace OpenViBE
@@ -0,0 +1,41 @@
#if defined(TARGET_HAS_ThirdPartyOgre3DTerrain)
#include "ovamsCCommandControlDiscreteOIS.h"
#include "ovamsCImpactApplication.h"
namespace OpenViBE {
namespace SSVEPMindShooter {
CCommandControlDiscreteOIS::CCommandControlDiscreteOIS(CImpactApplication* application)
: ICommandOIS(application) {}
void CCommandControlDiscreteOIS::processFrame()
{
ICommandOIS::processFrame();
CImpactApplication* application = dynamic_cast<CImpactApplication*>(m_application);
if (m_keysPressed[OIS::KC_UP] || m_keysPressed[OIS::KC_DOWN]) { application->getShip()->shoot(); }
if (m_keysPressed[OIS::KC_LEFT]) { application->getShip()->move(-6); }
if (m_keysPressed[OIS::KC_RIGHT]) { application->getShip()->move(6); }
}
void CCommandControlDiscreteOIS::receiveKeyPressedEvent(const OIS::KeyCode key)
{
if (key == OIS::KC_UP) { m_keysPressed[OIS::KC_UP] = true; }
if (key == OIS::KC_DOWN) { m_keysPressed[OIS::KC_DOWN] = true; }
if (key == OIS::KC_LEFT) { m_keysPressed[OIS::KC_LEFT] = true; }
if (key == OIS::KC_RIGHT) { m_keysPressed[OIS::KC_RIGHT] = true; }
}
void CCommandControlDiscreteOIS::receiveKeyReleasedEvent(const OIS::KeyCode key)
{
if (key == OIS::KC_UP) { m_keysPressed[OIS::KC_UP] = false; }
if (key == OIS::KC_DOWN) { m_keysPressed[OIS::KC_DOWN] = false; }
if (key == OIS::KC_LEFT) { m_keysPressed[OIS::KC_LEFT] = false; }
if (key == OIS::KC_RIGHT) { m_keysPressed[OIS::KC_RIGHT] = false; }
}
} // namespace SSVEPMindShooter
} // namespace OpenViBE
#endif
@@ -0,0 +1,27 @@
/// Control ship movements with the keyboard
#pragma once
#include <map>
#include "../ovamsICommandOIS.h"
namespace OpenViBE {
namespace SSVEPMindShooter {
class CImpactApplication;
class CCommandControlDiscreteOIS final : public ICommandOIS
{
public:
explicit CCommandControlDiscreteOIS(CImpactApplication* application);
~CCommandControlDiscreteOIS() override {}
void processFrame() override;
void receiveKeyPressedEvent(OIS::KeyCode key) override;
void receiveKeyReleasedEvent(OIS::KeyCode key) override;
private:
std::map<OIS::KeyCode, bool> m_keysPressed;
};
} // namespace SSVEPMindShooter
} // namespace OpenViBE
@@ -0,0 +1,59 @@
#if defined(TARGET_HAS_ThirdPartyOgre3DTerrain)
#include "ovamsCCommandImpactCustomTargetControl.h"
#include "ovamsCImpactApplication.h"
namespace OpenViBE {
namespace SSVEPMindShooter {
CCommandImpactCustomTargetControl::CCommandImpactCustomTargetControl(CImpactApplication* application)
: ICommandVRPNButton(application, "SSVEP_VRPN_TargetControl")
{
m_vrpnServer = CVRPNServer::getInstance(application);
m_vrpnServer->addButton("SSVEP_VRPN_TargetRequest", 1);
}
void CCommandImpactCustomTargetControl::processFrame()
{
CImpactApplication* application = dynamic_cast<CImpactApplication*>(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();
}
/// Add enemies on specified positions depending on the vrpn button triggered
void CCommandImpactCustomTargetControl::execute(const int button, const int /*state*/)
{
m_application->getLogManager() << Kernel::LogLevel_Info << "Adding target, position : " << button << "\n";
CImpactApplication* application = dynamic_cast<CImpactApplication*>(m_application);
application->m_NextOrigin = 0.0;
if (button == 0)
{
application->m_NextOrigin = -0.21F;
application->addTarget(1);
application->addTarget(6);
application->addTarget(4);
}
else if (button == 1)
{
application->m_NextOrigin = 0.21F;
application->addTarget(6);
application->addTarget(1);
application->addTarget(3);
}
}
} // namespace SSVEPMindShooter
} // namespace OpenViBE
#endif
@@ -0,0 +1,24 @@
#pragma once
/// Used to insert enemy ships into the scene upon receiving a trigger
#include "../ovamsICommandVRPNButton.h"
#include "../ovamsCVRPNServer.h"
namespace OpenViBE {
namespace SSVEPMindShooter {
class CImpactApplication;
class CCommandImpactCustomTargetControl final : public ICommandVRPNButton
{
public:
explicit CCommandImpactCustomTargetControl(CImpactApplication* application);
~CCommandImpactCustomTargetControl() override {}
void execute(const int button, const int state) override;
void processFrame() override;
private:
CVRPNServer* m_vrpnServer = nullptr;
};
} // namespace SSVEPMindShooter
} // namespace OpenViBE
@@ -0,0 +1,41 @@
#if defined(TARGET_HAS_ThirdPartyOgre3DTerrain)
#include "ovamsCCommandImpactTargetControl.h"
#include "ovamsCImpactApplication.h"
namespace OpenViBE {
namespace SSVEPMindShooter {
CCommandImpactTargetControl::CCommandImpactTargetControl(CImpactApplication* application)
: ICommandVRPNButton(application, "SSVEP_VRPN_TargetControl")
{
m_vrpnServer = CVRPNServer::getInstance(application);
m_vrpnServer->addButton("SSVEP_VRPN_TargetRequest", 1);
}
void CCommandImpactTargetControl::processFrame()
{
CImpactApplication* application = dynamic_cast<CImpactApplication*>(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 CCommandImpactTargetControl::execute(const int button, const int /*state*/)
{
m_application->getLogManager() << Kernel::LogLevel_Info << "Adding target, position : " << button << "\n";
dynamic_cast<CImpactApplication*>(m_application)->addTarget(button);
}
} // namespace SSVEPMindShooter
} // namespace OpenViBE
#endif
@@ -0,0 +1,23 @@
#pragma once
#include "../ovamsICommandVRPNButton.h"
#include "../ovamsCVRPNServer.h"
namespace OpenViBE {
namespace SSVEPMindShooter {
class CImpactApplication;
class CCommandImpactTargetControl final : public ICommandVRPNButton
{
public:
explicit CCommandImpactTargetControl(CImpactApplication* application);
~CCommandImpactTargetControl() override {}
void execute(const int button, const int state) override;
void processFrame() override;
private:
CVRPNServer* m_vrpnServer = nullptr;
};
} // namespace SSVEPMindShooter
} // namespace OpenViBE
@@ -0,0 +1,527 @@
#if defined(TARGET_HAS_ThirdPartyOgre3DTerrain)
#include "ovamsCImpactApplication.h"
#include "openvibe/ov_all.h"
#include "../ovamsCCommandStartStop.h"
#include "../ovamsCCommandStimulatorControl.h"
#include "../ovamsCCommandCamera.h"
#include "ovamsCCommandImpactTargetControl.h"
#include "ovamsCCommandImpactCustomTargetControl.h"
#include "ovamsCCommandControlAnalog.h"
#include "ovamsCCommandControlDiscrete.h"
#include "ovamsCCommandControlDiscreteOIS.h"
#include "../log/ovkCLogListenerFileBuffered.h"
#include <ctime>
#define DIALOG_CYCLES_TO_REMOVE 180
//#define NO_KEYBOARD
//#define NO_VRPN
#if !((CEGUI_VERSION_MAJOR > 0) || (CEGUI_VERSION_MINOR >= 8))
namespace CEGUI
{
typedef CEGUI::UVector2 USize;
};
#endif
namespace OpenViBE {
namespace SSVEPMindShooter {
CImpactApplication::CImpactApplication(const CString& scenarioDir, const CString& applicationSubtype)
: CApplication(scenarioDir), m_applicationSubtype(applicationSubtype) {}
CImpactApplication::~CImpactApplication()
{
(*m_logManager) << Kernel::LogLevel_Debug << "- m_ship\n";
delete m_ship;
}
bool CImpactApplication::setup(Kernel::IKernelContext* kernelCtx)
{
if (!CApplication::setup(kernelCtx)) { return false; }
Kernel::IConfigurationManager* configurationManager = &(m_kernelCtx->getConfigurationManager());
if (m_applicationSubtype == CString("shooter"))
{
// A config file appended for the online session
const CString configFile = m_ScenarioDir + "/appconf/shooter-configuration.conf";
if (!configurationManager->addConfigurationFromFile(configFile))
{
this->getLogManager() << Kernel::LogLevel_Error << "Unable to open [" << configFile << "]. Has the shooter-controller.lua been run?\n";
return false;
}
}
const uint64_t logLevel = kernelCtx->getTypeManager().getEnumerationEntryValueFromName(
OV_TypeId_LogLevel, configurationManager->expand("${SSVEP_LogLevel}"));
this->getLogManager() << Kernel::LogLevel_Info << "Parsed loglevel is " << logLevel << "\n";
if (logLevel != 0xffffffffffffffffULL) { kernelCtx->getLogManager().activate(Kernel::ELogLevel(logLevel), Kernel::LogLevel_Last, true); }
Kernel::ILogListener* logListenerFileBuffered = new Kernel::CLogListenerFileBuffered(*kernelCtx, "ssvep-mind-shooter-stimulator",
configurationManager->expand(
"${SSVEP_UserDataFolder}/mind-shooter-[$core{date}-$core{time}]-app.log"));
kernelCtx->getLogManager().addListener(logListenerFileBuffered);
m_sceneLoader = new DotSceneLoader();
std::stringstream enemyOrder;
enemyOrder << configurationManager->expand("${SSVEP_EnemyOrder}");
(*m_logManager) << Kernel::LogLevel_Info << "Enemy order: " << configurationManager->expand("${SSVEP_EnemyOrder}") << "\n";
while (enemyOrder.peek() != EOF)
{
int nextType;
enemyOrder >> nextType;
m_enemyOrder.push(nextType);
}
(*m_logManager) << Kernel::LogLevel_Debug << "Adding Impact game resources\n";
Ogre::ResourceGroupManager::getSingleton().addResourceLocation(
CString(configurationManager->expand("${Path_Data}/applications/${SSVEP_MindShooterFolderName}/resources/impact")).toASCIIString(), "FileSystem",
"SSVEPImpact", true);
Ogre::ResourceGroupManager::getSingleton().addResourceLocation(
CString(configurationManager->expand("${Path_Data}/applications/${SSVEP_MindShooterFolderName}/resources/impact/battleship")).toASCIIString(),
"FileSystem", "SSVEPImpact");
Ogre::ResourceGroupManager::getSingleton().addResourceLocation(
CString(configurationManager->expand("${Path_Data}/applications/${SSVEP_MindShooterFolderName}/resources/impact/battleship-destroyed")).toASCIIString(),
"FileSystem", "SSVEPImpact");
Ogre::ResourceGroupManager::getSingleton().addResourceLocation(
CString(configurationManager->expand("${Path_Data}/applications/${SSVEP_MindShooterFolderName}/resources/impact/enemy1")).toASCIIString(), "FileSystem",
"SSVEPImpact");
Ogre::ResourceGroupManager::getSingleton().addResourceLocation(
CString(configurationManager->expand("${Path_Data}/applications/${SSVEP_MindShooterFolderName}/resources/impact/enemy2")).toASCIIString(), "FileSystem",
"SSVEPImpact");
Ogre::ResourceGroupManager::getSingleton().addResourceLocation(
CString(configurationManager->expand("${Path_Data}/applications/${SSVEP_MindShooterFolderName}/resources/impact/enemy3")).toASCIIString(), "FileSystem",
"SSVEPImpact");
Ogre::ResourceGroupManager::getSingleton().addResourceLocation(
CString(configurationManager->expand("${Path_Data}/applications/${SSVEP_MindShooterFolderName}/resources/impact/ships")).toASCIIString(), "FileSystem",
"SSVEPImpact");
Ogre::ResourceGroupManager::getSingleton().addResourceLocation(
CString(configurationManager->expand("${Path_Data}/applications/${SSVEP_MindShooterFolderName}/resources/impact/starsky")).toASCIIString(),
"FileSystem", "SSVEPImpact");
Ogre::ResourceGroupManager::getSingleton().initialiseResourceGroup("SSVEPImpact");
setupScene();
// Create the StarShip object
(*m_logManager) << Kernel::LogLevel_Debug << "+ m_ship = new CStarShip(...)\n";
m_ship = new CImpactShip(this, m_sceneNode, &m_frequencies);
m_ship->activatePilotAssist(configurationManager->expandAsBoolean("${SSVEP_PilotAssist}"));
m_ship->activateTargetLockdown(configurationManager->expandAsBoolean("${SSVEP_TargetLockdown}") && (m_applicationSubtype == CString("shooter")));
m_ship->setFeedbackLevels(0, 0, 0);
m_ship->activateFeedback(configurationManager->expandAsBoolean("${SSVEP_Feedback}") && (m_applicationSubtype == CString("shooter")));
m_ship->activateFocusPoint(configurationManager->expandAsBoolean("${SSVEP_FocusPoint}"));
// Initialize the Target class
CImpactEnemyShip::initialize(this);
// create CEGUI windows
m_instructionWindow = static_cast<CEGUI::Window*>(m_guiWindowManager->createWindow("TaharezLook/StaticText", "InstructionsWindow"));
m_instructionWindow->setFont("BlueHighway-impact");
m_statusWindow = static_cast<CEGUI::Window*>(m_guiWindowManager->createWindow("TaharezLook/StaticText", "StatusWindow"));
m_statusWindow->setFont("BlueHighway-impact");
m_statusWindow->hide();
#if (CEGUI_VERSION_MAJOR > 0) || (CEGUI_VERSION_MINOR >= 8)
m_sheet->addChild(m_statusWindow);
m_sheet->addChild(m_instructionWindow);
#else
m_sheet->addChildWindow(m_statusWindow);
m_sheet->addChildWindow(m_instructionWindow);
#endif
// Create commands
#ifndef NO_KEYBOARD
(*m_logManager) << Kernel::LogLevel_Debug << "+ addCommand(new CCommandCamera(...)\n";
this->addCommand(new CCommandCamera(this));
(*m_logManager) << Kernel::LogLevel_Debug << "+ addCommand(new CCommandShipControlOIS(...))\n";
this->addCommand(new CCommandControlDiscreteOIS(this));
#endif
#ifndef NO_VRPN
(*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));
if (m_applicationSubtype == CString("trainer"))
{
(*m_logManager) << Kernel::LogLevel_Debug << "+ addCommand(new CCommandTargetControl(...)\n";
this->addCommand(new CCommandImpactTargetControl(this));
}
else
{
if (configurationManager->expandAsBoolean("${SSVEP_OneByOne}", false))
{
(*m_logManager) << Kernel::LogLevel_Debug << "+ addCommand(new CCommandTargetControl(...)\n";
this->addCommand(new CCommandImpactTargetControl(this));
}
else
{
(*m_logManager) << Kernel::LogLevel_Debug << "+ addCommand(new CCommandImpactCustomTargetControl(...)\n";
this->addCommand(new CCommandImpactCustomTargetControl(this));
}
const bool analogControls = configurationManager->expandAsBoolean("${SSVEP_AnalogControl}", false);
(*m_logManager) << Kernel::LogLevel_Debug << "+ addCommand(new CCommandControlAnalog(...))\n";
this->addCommand(new CCommandControlAnalog(this, analogControls));
(*m_logManager) << Kernel::LogLevel_Debug << "+ addCommand(new CCommandControlDiscrete(...))\n";
this->addCommand(new CCommandControlDiscrete(this, !analogControls));
(*m_logManager) << Kernel::LogLevel_Info << "Analog control mode: " << (analogControls ? "true" : "false") << "\n";
}
#endif
if (m_applicationSubtype == CString("shooter"))
{
m_gameState = IDLE_STARTED;
m_ship->moveToPosition();
// draw the initial text
m_instructionWindow->show();
m_instructionWindow->setSize(CEGUI::USize(CEGUI::UDim(0.50F, 0), CEGUI::UDim(0.10F, 0)));
m_instructionWindow->setPosition(CEGUI::UVector2(CEGUI::UDim(0.25F, 0), CEGUI::UDim(0.45F, 0)));
// m_instructionWindow->setText("Appuyez sur la touche ESPACE pour commencer le jeu ...");
m_instructionWindow->setText("Press SPACE to start the game ...");
}
else
{
m_gameState = IDLE_TRAINING;
// draw the initial text
m_instructionWindow->show();
m_instructionWindow->setSize(CEGUI::USize(CEGUI::UDim(0.50F, 0), CEGUI::UDim(0.15F, 0)));
m_instructionWindow->setPosition(CEGUI::UVector2(CEGUI::UDim(0.25F, 0), CEGUI::UDim(0.425F, 0)));
// m_instructionWindow->setText("Le systeme a besoin de faire quelques reglages.\nVeuillez vous concentrer sur les cibles indiques par les instructions.\n\nAppuyez sur la touche ESPACE pour commencer l'entrainement ...");
m_instructionWindow->setText(
"The system needs to calibrate.\nPlease concentrate on the targets as instructed.\n\nPlease press SPACE to start the process ...");
}
return true;
}
void CImpactApplication::setupScene() const
{
m_sceneManager->setAmbientLight(Ogre::ColourValue(1.0F, 1.0F, 1.0F));
m_camera->setNearClipDistance(5);
m_camera->setPosition(Ogre::Vector3(0, 100, 0));
m_camera->lookAt(0, 0, 1);
m_camera->move(Ogre::Vector3(0, 0, 0));
Ogre::Light* pointLight = m_sceneManager->createLight();
pointLight->setType(Ogre::Light::LT_POINT);
pointLight->setPosition(Ogre::Vector3(0, 50, 0));
pointLight->setDiffuseColour(1.0F, 1.0F, 0.8F);
pointLight->setSpecularColour(1.0F, 1.0F, 1.0F);
pointLight = m_sceneManager->createLight();
pointLight->setType(Ogre::Light::LT_POINT);
pointLight->setPosition(Ogre::Vector3(10, -10, 0));
pointLight->setDiffuseColour(0.5F, 0.0F, 0.0F);
m_sceneLoader->parseDotScene("v6.scene", "SSVEPImpact", m_sceneManager);
m_sceneManager->getSceneNode("v6_sky")->showBoundingBox(true);
m_sceneManager->getSceneNode("v6_sky")->scale(200.0, 300.0, 300.0);
m_sceneManager->getSceneNode("v6_sky")->translate(0.0, 100.0, 0.0);
}
bool CImpactApplication::enemyDestroyed(CImpactEnemyShip* es) { return es->isDestroyed(); }
void CImpactApplication::processFrame(const size_t frame)
{
CApplication::processFrame(frame);
//std::cout << m_window->getAverageFPS() << "\n";
m_ship->processFrame(frame);
m_ship->setTargetLocked(false);
m_sceneManager->getSceneNode("v6_sky")->pitch(Ogre::Radian(0.0001F));
if (m_gameState == STARTED)
{
size_t nEnemy = 0;
bool targetWasDestroyed = false;
int currentEnemyPointValue = 0;
if (m_CurrEnemy != nullptr) { currentEnemyPointValue = m_CurrEnemy->getPointValue(); }
m_CurrEnemy = nullptr;
for (auto it = m_targets.begin(); it != m_targets.end(); ++it)
{
(*it)->processFrame();
if ((*it)->isTouchable())
{
m_ship->evaluateHit(*it);
const Ogre::Vector2 enemyPosition = (*it)->getEnemyPosition();
if (enemyPosition.x > m_ship->getNormalizedPosition().x - (*it)->getWidth() / 2.0
&& enemyPosition.x < m_ship->getNormalizedPosition().x + (*it)->getWidth() / 2.0)
{
m_CurrEnemy = (*it);
m_ship->setTargetLocked(true);
if (currentEnemyPointValue != m_CurrEnemy->getPointValue())
{
m_ship->activateCannonInhibitor(m_CurrEnemy->getPointValue() < 0);
logPrefix() << "Targeting enemy : point value = " << m_CurrEnemy->getPointValue() << "\n";
}
}
if ((*it)->getPointValue() > 0) { nEnemy++; }
}
if ((*it)->isDestroyed())
{
m_score += (*it)->getPointValue();
delete *it;
m_statusWindow->setText(("Score: " + std::to_string(m_score)).c_str());
targetWasDestroyed = true;
}
}
if (currentEnemyPointValue != 0 && m_CurrEnemy == nullptr) { logPrefix() << "Focus on enemy lost\n"; }
if (targetWasDestroyed)
{
const size_t targetCount = m_targets.size();
m_targets.erase(std::remove_if(m_targets.begin(), m_targets.end(), enemyDestroyed), m_targets.end());
if (m_targets.empty() && m_targets.size() < targetCount) { m_TargetRequest = true; }
// if there are only friendly targets remaining make them leave
if (targetCount > 0 && nEnemy == 0)
{
for (auto it = m_targets.begin(); it != m_targets.end(); ++it) { if (!(*it)->m_EnemyLeaving) { (*it)->m_LeaveCountdown = 0; } }
}
}
}
if (m_dialogHideDelay > 0) { if (--m_dialogHideDelay == 0) { m_instructionWindow->hide(); } }
}
int CImpactApplication::getNextTargetType()
{
if (!m_enemyOrder.empty())
{
const int iNtt = m_enemyOrder.front();
m_enemyOrder.pop();
return iNtt;
}
return 0;
}
void CImpactApplication::addTarget(const size_t targetPosition)
{
float textSize = 0.25F;
logPrefix() << "Add Target : position = " << targetPosition << "\n";
getLogManager() << Kernel::LogLevel_Info << "Adding target on position " << targetPosition << "\n";
if (m_gameState == TRAINING)
{
switch (targetPosition)
{
case 0:
textSize = 0.35F;
// m_instructionWindow->setText("Regardez au milieu (MIDDLE) du vaisseau!");
m_instructionWindow->setText("Focus on the MIDDLE of the ship");
this->m_StimulusSender->sendStimulation(OVTK_StimulationId_Label_00);
break;
case 1:
textSize = 0.35F;
// m_instructionWindow->setText("Regardez le CANON (CANNON) du vaisseau pour tirer!");
m_instructionWindow->setText("Focus on the CANNON to fire!");
this->m_StimulusSender->sendStimulation(OVTK_StimulationId_Label_01);
break;
case 2:
textSize = 0.50F;
// m_instructionWindow->setText("Regardez l'aile GAUCHE (LEFT WING) du vaisseau pour de`placer le vaisseau vers la gauche");
m_instructionWindow->setText("Focus on the LEFT WING to turn the ship to the left");
this->m_StimulusSender->sendStimulation(OVTK_StimulationId_Label_02);
break;
case 3:
textSize = 0.50F;
// m_instructionWindow->setText("Regardez l'aile DROITE (RIGHT WING) du vaisseau pour de`placer le vaisseau vers la droite");
m_instructionWindow->setText("Focus on the RIGHT WING to turn the ship to the right");
this->m_StimulusSender->sendStimulation(OVTK_StimulationId_Label_03);
break;
default: break;
}
m_instructionWindow->setSize(CEGUI::USize(CEGUI::UDim(textSize, 0), CEGUI::UDim(0.10F, 0)));
m_instructionWindow->setPosition(CEGUI::UVector2(CEGUI::UDim((1.0F - textSize) / 2.0F, 0), CEGUI::UDim(0.45F, 0)));
m_instructionWindow->show();
m_dialogHideDelay = DIALOG_CYCLES_TO_REMOVE;
}
else if (m_gameState == STARTED)
{
// std::cout << (Ogre::Real( targetPosition ) - 3.5) / 7.0 * 100.0 << "\n";
if (!m_enemyOrder.empty()) { m_ship->returnToMiddleAndWaitForFoe(targetPosition, m_NextOrigin); }
else { getLogManager() << Kernel::LogLevel_Error << "No more enemy types\n"; }
}
}
void CImpactApplication::insertEnemy(const size_t targetPosition)
{
logPrefix() << "Creating Enemy : position = " << targetPosition << "\n";
m_targets.push_back(CImpactEnemyShip::createTarget((Ogre::Real(targetPosition) - 3.5F) / 7.0F * 100.0F));
}
void CImpactApplication::startFlickering()
{
m_instructionWindow->hide();
const size_t currentTime = size_t(time(nullptr) - m_startTime);
(*m_logManager) << Kernel::LogLevel_Info << currentTime << " > Starting Visual Stimulation\n";
m_active = true;
}
void CImpactApplication::stopFlickering()
{
const size_t currentTime = size_t(time(nullptr) - m_startTime);
(*m_logManager) << Kernel::LogLevel_Info << currentTime << " > Stopping Visual Stimulation\n";
m_active = false;
m_ship->setAllTargetsVisibility(true);
}
void CImpactApplication::startExperiment()
{
CApplication::startExperiment();
if (m_gameState == IDLE_TRAINING)
{
m_startTime = time(nullptr);
m_instructionWindow->hide();
m_dialogHideDelay = 0;
m_gameState = TRAINING;
m_ship->activatePilotAssist(false);
logPrefix() << "Start Experiment : IDLE_TRAINING -> TRAINING\n";
}
else if (m_gameState == IDLE_STARTED)
{
m_TargetRequest = true;
m_active = true;
m_instructionWindow->hide();
m_dialogHideDelay = 0;
m_statusWindow->setPosition(CEGUI::UVector2(CEGUI::UDim(0.0F, 0), CEGUI::UDim(0.0F, 0)));
m_statusWindow->setSize(CEGUI::USize(CEGUI::UDim(0.15F, 0), CEGUI::UDim(0.05F, 0)));
m_statusWindow->setText("Score: 0");
m_statusWindow->show();
m_gameState = STARTED;
logPrefix() << "Start Experiment : IDLE_STARTED -> STARTED\n";
}
}
void CImpactApplication::stopExperiment()
{
if (m_gameState == TRAINING)
{
if (m_applicationSubtype == CString("trainer"))
{
logPrefix() << "Stop Experiment : exiting\n";
this->exit();
}
else
{
const float textSize = 0.35F;
// m_instructionWindow->setText("L'application va prendre quelque temps pour le calcul, veuillez patienter.\nLe jeu va commencer automatiquement une fois l'application est prete.");
m_instructionWindow->setText(
"The application needs some time to compute, please be patient.\nThe game starts automatically when the application is ready.");
m_instructionWindow->setSize(CEGUI::USize(CEGUI::UDim(textSize, 0), CEGUI::UDim(0.10F, 0)));
m_instructionWindow->setPosition(CEGUI::UVector2(CEGUI::UDim((1.0F - textSize) / 2.0F, 0), CEGUI::UDim(0.45F, 0)));
m_instructionWindow->show();
logPrefix() << "Stop Experiment : Training Finished\n";
}
}
if (m_gameState == STARTED)
{
const float textSize = 0.45F;
m_instructionWindow->setText(("Bravo!\nYou have obtained " + std::to_string(m_score) + " points!\nPress ESC to close the program").c_str());
m_instructionWindow->setSize(CEGUI::USize(CEGUI::UDim(textSize, 0), CEGUI::UDim(0.10F, 0)));
m_instructionWindow->setPosition(CEGUI::UVector2(CEGUI::UDim((1.0F - textSize) / 2.0F, 0), CEGUI::UDim(0.45F, 0)));
m_instructionWindow->show();
m_active = false;
m_ship->setAllTargetsVisibility(true);
logPrefix() << "Stop Experiment : Game Ended\n";
}
}
void CImpactApplication::debugAction1()
{
(*m_logManager) << Kernel::LogLevel_Debug << "Debug Action 1 triggered\n";
this->startExperiment();
m_ship->activatePilotAssist(true);
}
void CImpactApplication::debugAction2()
{
(*m_logManager) << Kernel::LogLevel_Info << "Debug Action 2 triggered\n";
//if (m_TargetRequest && m_enemyOrder.size() > 2)
{
this->addTarget(1);
this->addTarget(6);
this->addTarget(4);
m_TargetRequest = false;
}
}
void CImpactApplication::debugAction3()
{
(*m_logManager) << Kernel::LogLevel_Info << "Debug Action 3 triggered\n";
m_TargetRequest = true;
}
void CImpactApplication::debugAction4()
{
(*m_logManager) << Kernel::LogLevel_Info << "Debug Action 4 triggered\n";
(*m_logManager) << Kernel::LogLevel_Info << "You (X: " << m_ship->getPosition().x << ", Y: " << m_ship->getPosition().y << ")\n";
if (!m_targets.empty())
{
const Ogre::Vector2 enemyPosition = m_targets[0]->getEnemyPosition();
(*m_logManager) << Kernel::LogLevel_Info << "Him (X: " << enemyPosition.x << ", Y: " << enemyPosition.y << ")\n";
}
}
} // namespace SSVEPMindShooter
} // namespace OpenViBE
#endif
@@ -0,0 +1,92 @@
#pragma once
#include <openvibe/ov_all.h>
#include <toolkit/ovtk_all.h>
#include "dotscene/DotSceneLoader.h"
#include "../ovamsCApplication.h"
#include "ovamsCImpactEnemyShip.h"
#include "ovamsCImpactShip.h"
#include <array>
namespace OpenViBE {
namespace SSVEPMindShooter {
class CImpactApplication final : public CApplication
{
public:
enum EGameState { BOOTING, IDLE_TRAINING, TRAINING, IDLE_STARTED, STARTED };
struct SStimulatorState
{
float ship_position;
std::array<double, 3> feedback_level;
int ship_direction;
bool shooting;
};
struct SGameState
{
int movements_right;
int movements_left;
int shoots_fired;
};
CImpactApplication(const CString& scenarioDir, const CString& applicationSubtype);
~CImpactApplication() override;
bool setup(Kernel::IKernelContext* kernelCtx) override;
CImpactShip* getShip() const { return m_ship; }
bool isActive() const { return m_active; }
void startExperiment() override;
void stopExperiment() override;
void startFlickering() override;
void stopFlickering() override;
void debugAction1() override;
void debugAction2() override;
void debugAction3() override;
void debugAction4() override;
int getNextTargetType();
void addTarget(size_t targetPosition);
void insertEnemy(size_t targetPosition);
CImpactEnemyShip* getCurrentEnemy() const { return m_CurrEnemy; }
CString getSubtype() const { return m_applicationSubtype; }
EGameState getState() const { return m_gameState; }
DotSceneLoader* getSceneLoader() const { return m_sceneLoader; }
CEGUI::Window* getInstructionWindow() const { return m_instructionWindow; }
CImpactEnemyShip* m_CurrEnemy = nullptr;
bool m_TargetRequest = false;
Ogre::Real m_NextOrigin = 0.0;
private:
void setupScene() const;
void processFrame(const size_t frame) override;
static bool enemyDestroyed(CImpactEnemyShip* /*es*/);
CString m_applicationSubtype;
EGameState m_gameState = BOOTING;
std::queue<int> m_enemyOrder;
bool m_active = false;
time_t m_startTime;
DotSceneLoader* m_sceneLoader = nullptr;
CEGUI::Window* m_statusWindow = nullptr;
CEGUI::Window* m_instructionWindow = nullptr;
size_t m_dialogHideDelay = 0;
CImpactShip* m_ship = nullptr;
std::vector<CImpactEnemyShip*> m_targets;
int m_score = 0;
};
} // namespace SSVEPMindShooter
} // namespace OpenViBE
@@ -0,0 +1,258 @@
#if defined(TARGET_HAS_ThirdPartyOgre3DTerrain)
#include "ovamsCImpactEnemyShip.h"
#include "ovamsCImpactApplication.h"
#define IMPACTSHIP_SIZE 0.2f
#define SCREEN_RATIO ( 16.0f / 9.0f )
namespace OpenViBE {
namespace SSVEPMindShooter {
CImpactApplication* CImpactEnemyShip::m_application = nullptr;
Ogre::SceneNode* CImpactEnemyShip::m_parentNode = nullptr;
CBasicPainter* CImpactEnemyShip::m_painter = nullptr;
int CImpactEnemyShip::m_nCurrentExplosion = 0;
void CImpactEnemyShip::initialize(CImpactApplication* application)
{
m_application = application;
m_painter = m_application->getPainter();
m_parentNode = m_application->getSceneNode();
}
CImpactEnemyShip* CImpactEnemyShip::createTarget(const Ogre::Real position)
{
if (m_application == nullptr)
{
std::cerr << "The CImpactEnemyShip was not initialized" << std::endl;
return nullptr;
}
return new CImpactEnemyShip(position);
}
CImpactEnemyShip::CImpactEnemyShip(const Ogre::Real position)
{
m_EnemyLeaving = false;
const int type = m_application->getNextTargetType();
m_application->logPrefix() << "Creating enemy " << type << "\n";
if (type > 0 && type <= 6)
{
switch (type)
{
case 1:
m_application->getSceneLoader()->parseDotScene("v2.scene", "SSVEPImpact", m_application->getSceneManager());
m_enemyNode = m_application->getSceneManager()->getSceneNode("v2_vaisseau");
m_enemyNode->scale(1.0F, 1.0F, 1.0F);
m_shipWidth = 0.5F;
m_LeaveCountdown = int(2.0F * 3600);
m_pointValue = 100;
break;
case 2:
m_application->getSceneLoader()->parseDotScene("v1.scene", "SSVEPImpact", m_application->getSceneManager());
m_enemyNode = m_application->getSceneManager()->getSceneNode("v1_vaisseau");
m_enemyNode->scale(1.9F, 1.9F, 1.9F);
m_shipWidth = 0.45F;
m_LeaveCountdown = int(1.5F * 3600);
m_pointValue = 200;
break;
case 3:
m_application->getSceneLoader()->parseDotScene("v3.scene", "SSVEPImpact", m_application->getSceneManager());
m_enemyNode = m_application->getSceneManager()->getSceneNode("v3_vaisseau");
m_enemyNode->scale(2.2F, 2.0F, 2.0F);
m_shipWidth = 0.4F;
m_LeaveCountdown = int(1.0F * 3600);
m_pointValue = 400;
break;
case 4:
m_application->getSceneLoader()->parseDotScene("ship-cheap.scene", "SSVEPImpact", m_application->getSceneManager());
m_enemyNode = m_application->getSceneManager()->getSceneNode("ship-cheap_node");
m_pointValue = 500;
break;
case 5:
m_application->getSceneLoader()->parseDotScene("ship-costly.scene", "SSVEPImpact", m_application->getSceneManager());
m_enemyNode = m_application->getSceneManager()->getSceneNode("ship-costly_node");
m_pointValue = 1500;
break;
case 6:
m_application->getSceneLoader()->parseDotScene("ship-friend.scene", "SSVEPImpact", m_application->getSceneManager());
m_enemyNode = m_application->getSceneManager()->getSceneNode("ship-friend_node");
m_pointValue = -500;
break;
default:
break;
}
if (type >= 4 && type <= 6)
{
m_enemyNode->scale(1.2F, 1.2F, 1.2F);
m_shipWidth = 0.3F;
m_LeaveCountdown = int(1.0F * 3600);
}
m_enemyNode->yaw(Ogre::Radian(Ogre::Math::PI));
m_hitBox = m_application->getSceneNode()->createChildSceneNode();
//m_hitBox->attachObject(m_painter->paintTriangle(Vector2(+ m_shipWidth / 2, +0.9), Vector2(- m_shipWidth / 2, +0.9), Vector2( 0.0, +0.5)));
m_hitBox->translate(position / 70.0F, 1.2F, 0.0F, Ogre::Node::TS_LOCAL);
m_enemyNode->translate(position, 0.0F, -60.0F, Ogre::Node::TS_LOCAL);
m_incomingStatus = 30.0F;
}
else { m_application->getLogManager() << Kernel::LogLevel_Fatal << "Unknown enemy type " << type << " ! The application will now crash!\n"; }
}
void CImpactEnemyShip::destroyAllAttachedMovableObjects(Ogre::SceneNode* sceneNode)
{
if (!sceneNode) { return; }
// Destroy all the attached objects
Ogre::SceneNode::ObjectIterator itObject = sceneNode->getAttachedObjectIterator();
while (itObject.hasMoreElements())
{
Ogre::MovableObject* pObject = static_cast<Ogre::MovableObject*>(itObject.getNext());
sceneNode->getCreator()->destroyMovableObject(pObject);
}
Ogre::SceneNode::ChildNodeIterator itChild = sceneNode->getChildIterator();
while (itChild.hasMoreElements())
{
Ogre::SceneNode* pChildNode = dynamic_cast<Ogre::SceneNode*>(itChild.getNext());
destroyAllAttachedMovableObjects(pChildNode);
}
}
CImpactEnemyShip::~CImpactEnemyShip()
{
m_application->logPrefix() << "Enemy Destroyed\n";
destroyAllAttachedMovableObjects(m_enemyNode);
m_enemyNode->removeAndDestroyAllChildren();
m_enemyNode->getCreator()->destroySceneNode(m_enemyNode);
destroyAllAttachedMovableObjects(m_hitBox);
m_hitBox->removeAndDestroyAllChildren();
m_hitBox->getCreator()->destroySceneNode(m_hitBox);
}
void CImpactEnemyShip::processFrame()
{
// oscillation animation
static int oscillator = 90;
if (m_LeaveCountdown > 0 && !m_EnemyLeaving) { m_LeaveCountdown--; }
if (m_LeaveCountdown == 0 && !m_EnemyLeaving)
{
m_application->logPrefix() << "Enemy Leaving\n";
m_EnemyLeaving = true;
m_pointValue = 0;
}
if (!m_EnemyLeaving)
{
oscillator++;
oscillator = oscillator % 360;
// m_enemyNode->roll(Radian(Math::Sin(Degree(sin_oscillator)) / 80));
m_enemyNode->translate(Ogre::Math::Sin(Ogre::Degree(Ogre::Real(oscillator))) / 20.0F * 0,
Ogre::Math::Sin(Ogre::Degree(Ogre::Real(oscillator * 2 + 90))) / 20, 0.0F, Ogre::Node::TS_LOCAL);
m_hitBox->translate(Ogre::Math::Sin(Ogre::Degree(Ogre::Real(oscillator))) / 20.0F / 50.0F * 0, 0.0F, 0.0F, Ogre::Node::TS_LOCAL);
// incoming enemy animation
if (m_incomingStatus > 0)
{
m_hitBox->translate(0.0F, -0.04F, 0.0F, Ogre::Node::TS_LOCAL);
m_enemyNode->translate(0.0F, 0.0F, 1.0F, Ogre::Node::TS_LOCAL);
m_incomingStatus -= 1.0F;
}
// exploding ship animation
if (m_destructionStatus > 3)
{
m_destructionStatus++;
m_enemyNode->translate(0.1F, 2, 1, Ogre::Node::TS_PARENT);
m_enemyNode->rotate(Ogre::Vector3(0.3F, 0.25F, 1.0F), Ogre::Radian(3.14F / 20.0F), Ogre::Node::TS_LOCAL);
m_enemyNode->scale(0.95F, 0.95F, 0.95F);
}
}
else
{
m_enemyNode->translate(0.0F, -1.0F, float(m_LeaveCountdown) * 0.5F, Ogre::Node::TS_LOCAL);
m_LeaveCountdown++;
if (m_enemyNode->getPosition().z < -100)
{
m_shipDestroyed = true;
m_application->logPrefix() << "Enemy Left : marked as destroyed\n";
}
}
if (m_destructionStatus > 50)
{
m_shipDestroyed = true;
if (this->getPointValue() > 0) { m_application->logPrefix() << "Enemy Shot Down : marked as destroyed\n"; }
else { m_application->logPrefix() << "Friendly Target Shot Down : marked as destroyed\n"; }
}
// handle the explosions
for (auto it = m_explosions.begin(); it != m_explosions.end(); ++it)
{
(*it)->ttl--;
if ((*it)->ttl < 4 && (*it)->ttl >= 0)
{
Ogre::ParticleEmitter* emitter = (*it)->particleSystem->getEmitter(0);
emitter->setEmissionRate(emitter->getEmissionRate() - 50);
}
if (explostionExhausted(*it))
{
m_painter->getSceneManager()->destroyParticleSystem((*it)->particleSystem);
(*it)->node->getCreator()->destroySceneNode((*it)->node);
delete *it;
}
}
m_explosions.erase(std::remove_if(m_explosions.begin(), m_explosions.end(), explostionExhausted), m_explosions.end());
}
void CImpactEnemyShip::processHit(const Ogre::Vector2 point)
{
// set status of the ship as exploding
if (m_destructionStatus <= 3)
{
m_destructionStatus++;
m_application->logPrefix() << "Enemy Lost a Hitpoint : current hits = " << m_destructionStatus << "\n";
}
// create the explosion upon hit
struct SExplosionAnimation* explosion = new struct SExplosionAnimation;
const char* projectileName = ("Explosion " + std::to_string(++m_nCurrentExplosion)).c_str();
explosion->particleSystem = m_painter->getSceneManager()->createParticleSystem(projectileName, "Particle/Explosion");
explosion->ttl = 25;
explosion->node = m_parentNode->createChildSceneNode();
explosion->node->attachObject(explosion->particleSystem);
explosion->node->translate(point.x * -65.0F, 0.0F, 30.0F, Ogre::Node::TS_WORLD);
m_explosions.push_back(explosion);
}
} // namespace SSVEPMindShooter
} // namespace OpenViBE
#endif
@@ -0,0 +1,61 @@
#pragma once
#include <Ogre.h>
#include "../ovamsCBasicPainter.h"
#define SSVEP_SHOOTER_TARGET_SIZE 0.15f
namespace OpenViBE {
namespace SSVEPMindShooter {
class CImpactApplication;
class CImpactEnemyShip
{
public:
static CImpactEnemyShip* createTarget(Ogre::Real position);
static void initialize(CImpactApplication* application);
~CImpactEnemyShip();
void processFrame();
void processHit(Ogre::Vector2 point);
Ogre::Vector2 getEnemyPosition() const { return Ogre::Vector2(m_hitBox->getPosition().x, m_hitBox->getPosition().y); }
bool isDestroyed() const { return m_shipDestroyed; }
bool isTouchable() const { return m_destructionStatus < 10 && !m_EnemyLeaving; }
int getPointValue() const { return m_pointValue; }
Ogre::Real getWidth() const { return m_shipWidth; }
int m_LeaveCountdown = 0;
bool m_EnemyLeaving = false;
private:
struct SExplosionAnimation
{
Ogre::ParticleSystem* particleSystem;
Ogre::SceneNode* node;
int ttl;
};
static bool explostionExhausted(struct SExplosionAnimation* ea) { return ea->ttl < -25; }
static void destroyAllAttachedMovableObjects(Ogre::SceneNode* sceneNode);
static CImpactApplication* m_application;
static Ogre::SceneNode* m_parentNode;
static CBasicPainter* m_painter;
Ogre::SceneNode* m_enemyNode = nullptr;
Ogre::SceneNode* m_hitBox = nullptr;
Ogre::Real m_incomingStatus = 0;
Ogre::Real m_shipWidth = 0.1F;
Ogre::uint32 m_destructionStatus = 0;
bool m_shipDestroyed = false;
int m_pointValue = 100;
explicit CImpactEnemyShip(Ogre::Real position);
static int m_nCurrentExplosion;
std::vector<struct SExplosionAnimation*> m_explosions;
};
} // namespace SSVEPMindShooter
} // namespace OpenViBE
@@ -0,0 +1,403 @@
#if defined(TARGET_HAS_ThirdPartyOgre3DTerrain)
#include "ovamsCImpactShip.h"
#include "ovamsCImpactEnemyShip.h"
#include "ovamsCImpactApplication.h"
#include "../ovamsCSSVEPFlickeringObject.h"
#define SSVEP_SHIP_HULL_COLOUR Ogre::ColourValue(0.0f, 0.5f, 0.5f)
#define SIGN(x) ( (x) < 0 ? -1 : 1 )
#define SCREEN_RATIO ( 16.0f / 9.0f )
#define IMPACTSHIP_SIZE 0.2f
#define IMPACTSHIP_SPEEDFACTOR 0.7f
namespace OpenViBE {
namespace SSVEPMindShooter {
//SP CImpactShip::CImpactShip(CImpactApplication* application, Ogre::SceneNode* parentNode, std::vector<std::pair<size_t, size_t> >* pFrequencies) :
CImpactShip::CImpactShip(CImpactApplication* application, Ogre::SceneNode* parentNode, std::vector<size_t>* pFrequencies)
: m_application(application), m_currentAngle(0)
{
m_application->getLogManager() << Kernel::LogLevel_Info << "Loading ship\n";
m_application->getSceneLoader()->parseDotScene("v5.scene", "SSVEPImpact", m_application->getSceneManager());
m_targetStates[0] = TS_NORMAL;
m_targetStates[1] = TS_NORMAL;
m_targetStates[2] = TS_NORMAL;
Ogre::SceneManager* sceneManager = m_application->getSceneManager();
m_projectilesNode = parentNode->createChildSceneNode();
m_shipNode = sceneManager->getSceneNode("battleship");
m_shipNode->scale(0.6F, 0.6F, 0.6F);
m_shipNode->yaw(Ogre::Radian(-Ogre::Math::PI / 2.0F));
m_shipNode->translate(-25.0F, 0.0F, 0.0F, Ogre::Node::TS_LOCAL);
if (!pFrequencies || pFrequencies->size() < 4)
{
std::cout << "Error: Expected the frequencies vector to contain indexes 0...3 but its size is " << (pFrequencies ? pFrequencies->size() : -1) <<
". Crash is likely imminent.\n";
}
sceneManager->getSceneNode("v5_ecran_avant2")->setVisible(false);
m_shipCannon = new CSSVEPFlickeringObject(sceneManager->getSceneNode("shipCannon"), (*pFrequencies)[1]);
sceneManager->getSceneNode("v5_aile_gauche2")->setVisible(false);
m_shipLeftWing = new CSSVEPFlickeringObject(sceneManager->getSceneNode("shipLeftWing"), (*pFrequencies)[2]);
sceneManager->getSceneNode("v5_aile_droite2")->setVisible(false);
m_shipRightWing = new CSSVEPFlickeringObject(sceneManager->getSceneNode("shipRightWing"), (*pFrequencies)[3]);
sceneManager->getSceneNode("feedback")->setVisible(true);
m_targetingNode = sceneManager->getSceneNode("v5_viseur");
}
void CImpactShip::activatePilotAssist(const bool activate)
{
m_pilotAssistActive = activate;
m_application->logPrefix() << "Pilot Assist : " << (activate ? "ON" : "OFF") << "\n";
}
void CImpactShip::activateCannonInhibitor(const bool activate)
{
m_cannonInhibited = activate;
m_application->logPrefix() << "Cannon Inhibitor : " << (activate ? "ON" : "OFF") << "\n";
}
void CImpactShip::activateTargetLockdown(const bool activate)
{
m_targetLockdownActive = activate;
m_application->logPrefix() << "Target Lockdown : " << (activate ? "ON" : "OFF") << "\n";
}
void CImpactShip::activateFeedback(const bool activate)
{
m_feedbackActive = activate;
m_application->getSceneManager()->getSceneNode("feedback")->setVisible(activate);
m_application->logPrefix() << "Feedback : " << (activate ? "ON" : "OFF") << "\n";
}
void CImpactShip::activateFocusPoint(const bool activate)
{
m_focusPointActive = activate;
m_application->getSceneManager()->getSceneNode("feedback")->setVisible(!m_focusPointActive && m_feedbackActive);
if (activate)
{
m_application->getSceneManager()->getSceneNode("v5_a1a")->setVisible(false);
m_application->getSceneManager()->getSceneNode("v5_a2a")->setVisible(true);
m_application->getSceneManager()->getSceneNode("v5_a3a")->setVisible(false);
m_application->getSceneManager()->getSceneNode("v5_g1a")->setVisible(true);
m_application->getSceneManager()->getSceneNode("v5_g2a")->setVisible(false);
m_application->getSceneManager()->getSceneNode("v5_g3a")->setVisible(false);
m_application->getSceneManager()->getSceneNode("v5_d1a")->setVisible(true);
m_application->getSceneManager()->getSceneNode("v5_d2a")->setVisible(false);
m_application->getSceneManager()->getSceneNode("v5_d3a")->setVisible(false);
}
m_application->logPrefix() << "FocusPoint : " << (activate ? "ON" : "OFF") << "\n";
}
bool CImpactShip::projectileExhausted(struct SBlasterProjectile* bp) { return bp->iTTL <= 0; }
void CImpactShip::setAllTargetsVisibility(const bool visible) const
{
m_shipCannon->setVisible(visible);
m_shipLeftWing->setVisible(visible);
m_shipRightWing->setVisible(visible);
}
void CImpactShip::processFrame(const size_t /*currentFrame*/)
{
if (m_shootingCooldown > 0) { m_shootingCooldown--; }
if (m_application->isActive())
{
// deactivate the wing targets when the ship is on the border
// std::cout << this->getNormalizedPosition() << "\n";
if (getNormalizedPosition().x >= -0.75 || !m_targetLockdownActive)
{
m_shipLeftWing->processFrame();
m_targetStates[1] = TS_NORMAL;
}
else
{
m_shipLeftWing->setVisible(false);
m_targetStates[1] = TS_OFF;
}
if (getNormalizedPosition().x <= 0.75 || !m_targetLockdownActive)
{
m_shipRightWing->processFrame();
m_targetStates[2] = TS_NORMAL;
}
else
{
m_shipRightWing->setVisible(false);
m_targetStates[2] = TS_OFF;
}
// deactivate the cannon when there is no target locked
if (m_targetLocked || (!m_targetLockdownActive))
{
m_shipCannon->processFrame();
m_targetStates[0] = (m_cannonInhibited ? TS_INHIBITED : TS_NORMAL);
}
else
{
m_shipCannon->setVisible(false);
m_targetStates[0] = TS_OFF;
}
}
m_targetingNode->pitch(Ogre::Degree(2), Ogre::Node::TS_PARENT);
if (m_targetLocked) { m_targetingNode->setVisible(true); }
else { m_targetingNode->setVisible(false); }
/*
if (m_prepareAnimationFrame > 0)
{
m_shipNode->translate(0.0f, -0.01f, 0.0f);
m_prepareAnimationFrame--;
}
*/
if (m_returning)
{
if (getNormalizedPosition().x < m_origin - 5e-2 || getNormalizedPosition().x > m_origin + 5e-2)
{
m_nCurrentDisplacement = (getNormalizedPosition().x < m_origin) ? 1 : -1;
}
else
{
m_application->logPrefix() << "Ship Returned to Initial Position\n";
m_returning = false;
m_application->startFlickering();
while (!m_nextEnemyPosition.empty())
{
const size_t nextEnemyPosition = m_nextEnemyPosition.front();
m_nextEnemyPosition.pop_front();
m_application->insertEnemy(nextEnemyPosition);
}
}
}
if (m_nCurrentDisplacement != 0)
{
// m_application->logPrefix() << "Displacement Vector : value = " << m_nCurrentDisplacement << "\n";
if (m_returning || !m_targetLocked || !m_pilotAssistActive)
{
m_application->logPrefix() << "Ship Moving : direction " << (m_nCurrentDisplacement > 0 ? "left" : "right") << ", full speed\n";
m_shipNode->translate(0.5F * -float(SIGN(m_nCurrentDisplacement)) * IMPACTSHIP_SPEEDFACTOR, 0.0F, 0.0F);
}
else
{
Ogre::Real slowdown = 0.0;
if (m_application->getCurrentEnemy() != nullptr && m_application->getCurrentEnemy()->getPointValue() > 0)
{
const Ogre::Real enemyPos = m_application->getCurrentEnemy()->getEnemyPosition().x;
const Ogre::Real shipPos = getNormalizedPosition().x;
if (fabs(enemyPos - shipPos) < m_application->getCurrentEnemy()->getWidth() / 2)
{
const Ogre::Real distance = fabs(shipPos - enemyPos) / (m_application->getCurrentEnemy()->getWidth() / 2);
if (SIGN(m_nCurrentDisplacement) == SIGN(shipPos - enemyPos)) { slowdown = 1.0F - distance * distance * distance; }
if (SIGN(m_nCurrentDisplacement) > 0) { m_targetStates[2] = TS_INHIBITED; }
else { m_targetStates[1] = TS_INHIBITED; }
}
}
m_application->logPrefix() << "Ship Moving : direction " << (m_nCurrentDisplacement > 0 ? "left" : "right") << ", slowdown = " << slowdown << "\n";
m_shipNode->translate((0.5F - slowdown * 0.3F) * -float(SIGN(m_nCurrentDisplacement)) * IMPACTSHIP_SPEEDFACTOR, 0.0F, 0.0F);
}
// m_targetingNode->translate( 0.007f * SIGN(m_nCurrentDisplacement), 0.0f, 0.0f );
m_nCurrentDisplacement -= SIGN(m_nCurrentDisplacement);
}
for (auto it = m_projectiles.begin(); it != m_projectiles.end(); ++it)
{
(*it)->iTTL--;
(*it)->pNode->translate(0.0, -2.0, 0.0, Ogre::Node::TS_LOCAL);
(*it)->rRelY -= 1.0F / 65.0F;
if (projectileExhausted(*it))
{
m_application->getSceneManager()->destroyParticleSystem((*it)->pParticleSystem);
(*it)->pNode->getCreator()->destroySceneNode((*it)->pNode);
delete *it;
}
}
m_projectiles.erase(std::remove_if(m_projectiles.begin(), m_projectiles.end(), projectileExhausted), m_projectiles.end());
if (m_oldPosition != m_shipNode->getPosition().x)
{
m_oldPosition = m_shipNode->getPosition().x;
m_application->logPrefix() << "New Ship Position : " << m_oldPosition << " / Normalized X : " << getNormalizedPosition().x << "\n";
}
}
void CImpactShip::move(const int displacement)
{
if (displacement < 0 && getNormalizedPosition().x <= -0.75) { return; }
if (displacement > 0 && getNormalizedPosition().x >= 0.75) { return; }
//m_application->logPrefix() << "Move : diff vector = " << displacement << ", current vector = " << m_nCurrentDisplacement;
if (abs(m_nCurrentDisplacement) < 6) { m_nCurrentDisplacement += displacement; }
//m_application->getLogManager() << ", resulting vector = " << m_nCurrentDisplacement << "\n";
}
void CImpactShip::shoot()
{
m_application->logPrefix() << "Shoot : ";
if (m_targetLockdownActive && !m_targetLocked)
{
m_application->logPrefix() << "CANCELED : pilot assist blocked the shot\n";
return;
}
if (m_shootingCooldown > 0)
{
m_application->logPrefix() << "CANCELED : shooting cooldown blocked the shot\n";
return;
}
m_shootingCooldown = (m_targetStates[0] == TS_INHIBITED) ? 24 : 12;
struct SBlasterProjectile* projectile = new struct SBlasterProjectile;
const std::string projectileName = "Projectile_" + std::to_string(++m_nShot);
projectile->pParticleSystem = m_application->getSceneManager()->createParticleSystem(projectileName, "Particle/PurpleFountain");
projectile->iTTL = 70;
projectile->pNode = m_projectilesNode->createChildSceneNode();
projectile->pNode->pitch(Ogre::Radian(-Ogre::Math::PI / 2.0F));
projectile->pNode->translate(this->getPosition().x, 20.0, 0.0, Ogre::Node::TS_LOCAL);
projectile->pNode->attachObject(projectile->pParticleSystem);
projectile->rRelX = -m_shipNode->getPosition().x / 70.0F;
projectile->rRelY = 0.6F;
m_application->getLogManager() << "OK : creating particle system\n";
m_projectiles.push_back(projectile);
}
void CImpactShip::setFeedbackLevels(const int f1, int f2, int f3)
{
if (m_focusPointActive) { return; }
Ogre::SceneManager* sceneManager = m_application->getSceneManager();
if (m_targetStates[1] == TS_OFF) { f2 = 0; }
if (m_targetStates[2] == TS_OFF) { f3 = 0; }
sceneManager->getSceneNode("v5_a1b")->setVisible(false);
sceneManager->getSceneNode("v5_a2b")->setVisible(false);
sceneManager->getSceneNode("v5_a3b")->setVisible(false);
sceneManager->getSceneNode("v5_g1b")->setVisible(false);
sceneManager->getSceneNode("v5_g2b")->setVisible(false);
sceneManager->getSceneNode("v5_g3b")->setVisible(false);
sceneManager->getSceneNode("v5_d1b")->setVisible(false);
sceneManager->getSceneNode("v5_d2b")->setVisible(false);
sceneManager->getSceneNode("v5_d3b")->setVisible(false);
if (m_feedbackActive)
{
int nActives = 0;
if (f1 > 0) { sceneManager->getSceneNode("v5_a1b")->setVisible(true); }
if (f1 > 1) { sceneManager->getSceneNode("v5_a2b")->setVisible(true); }
if (f1 > 2)
{
sceneManager->getSceneNode("v5_a3b")->setVisible(true);
nActives++;
}
if (f2 > 0) { sceneManager->getSceneNode("v5_g1b")->setVisible(true); }
if (f2 > 1) { sceneManager->getSceneNode("v5_g2b")->setVisible(true); }
if (f2 > 2)
{
sceneManager->getSceneNode("v5_g3b")->setVisible(true);
nActives++;
}
if (f3 > 0) { sceneManager->getSceneNode("v5_d1b")->setVisible(true); }
if (f3 > 1) { sceneManager->getSceneNode("v5_d2b")->setVisible(true); }
if (f3 > 2)
{
sceneManager->getSceneNode("v5_d3b")->setVisible(true);
nActives++;
}
if (nActives > 1)
{
sceneManager->getSceneNode("v5_a3b")->setVisible(false);
sceneManager->getSceneNode("v5_g3b")->setVisible(false);
sceneManager->getSceneNode("v5_d3b")->setVisible(false);
}
if (m_targetLockdownActive && !m_targetLocked)
{
sceneManager->getSceneNode("v5_a1b")->setVisible(false);
sceneManager->getSceneNode("v5_a2b")->setVisible(false);
sceneManager->getSceneNode("v5_a3b")->setVisible(false);
}
}
}
void CImpactShip::returnToMiddleAndWaitForFoe(const size_t targetPosition, const Ogre::Real position)
{
m_application->logPrefix() << "Ship Returning to Middle Position\n";
m_nextEnemyPosition.push_back(targetPosition);
m_application->stopFlickering();
m_origin = position;
m_returning = true;
}
bool CImpactShip::evaluateHit(CImpactEnemyShip* enemy)
{
const Ogre::Vector2 point = enemy->getEnemyPosition();
// std::cout << "enemy:" << enemy->getEnemyPosition() << "\n";
for (auto it = m_projectiles.begin(); it != m_projectiles.end(); ++it)
{
// std::cout << "proj: " << (*it)->rRelX << " " << (*it)->rRelY << "\n";
if (Ogre::Math::pointInTri2D(Ogre::Vector2((*it)->rRelX, (*it)->rRelY),
Ogre::Vector2(point.x + enemy->getWidth() / 2.0F, point.y + enemy->getWidth() / 2.0F),
Ogre::Vector2(point.x - enemy->getWidth() / 2.0F, point.y + enemy->getWidth() / 2.0F),
Ogre::Vector2(point.x, point.y - 0.1F)))
{
m_application->logPrefix() << "Enemy Hit!\n";
(*it)->iTTL = 1;
enemy->processHit(Ogre::Vector2((*it)->rRelX, (*it)->rRelY));
return true;
}
}
return false;
}
} // namespace SSVEPMindShooter
} // namespace OpenViBE
#endif
@@ -0,0 +1,89 @@
#pragma once
#include <vector>
#include <Ogre.h>
#include <openvibe/ov_all.h>
#include <toolkit/ovtk_all.h>
namespace OpenViBE {
namespace SSVEPMindShooter {
class CImpactApplication;
class CImpactEnemyShip;
class CSSVEPFlickeringObject;
class CImpactShip
{
public:
enum ETargetState { TS_NORMAL, TS_INHIBITED, TS_OFF };
//SP CImpactShip( CImpactApplication* application, Ogre::SceneNode* parentNode, std::vector<std::pair<size_t, size_t> >* pFrequencies);
CImpactShip(CImpactApplication* application, Ogre::SceneNode* parentNode, std::vector<size_t>* pFrequencies);
void processFrame(const size_t currentFrame);
void moveToPosition() { m_prepareAnimationFrame = 70; }
void move(int displacement);
void shoot();
bool evaluateHit(CImpactEnemyShip* enemy);
void setAllTargetsVisibility(bool visible) const;
Ogre::Vector2 getPosition() const { return Ogre::Vector2(m_shipNode->getPosition().x, m_shipNode->getPosition().y); }
Ogre::Vector2 getNormalizedPosition() const { return Ogre::Vector2(-m_shipNode->getPosition().x / 70.0F, m_shipNode->getPosition().y); }
void setTargetLocked(const bool targetLocked) { m_targetLocked = targetLocked; }
void setFeedbackLevels(int f1, int f2, int f3);
void activatePilotAssist(const bool activate);
void activateCannonInhibitor(const bool activate);
void activateTargetLockdown(const bool activate);
void activateFeedback(const bool activate);
void activateFocusPoint(const bool activate);
void returnToMiddleAndWaitForFoe(size_t targetPosition, Ogre::Real position = 0.0);
ETargetState getTargetState(const int target) { return m_targetStates[target]; }
private:
struct SBlasterProjectile
{
Ogre::ParticleSystem* pParticleSystem;
Ogre::SceneNode* pNode;
Ogre::SceneNode* pOutlineNode;
int iTTL;
Ogre::Real rRelX, rRelY;
};
static bool projectileExhausted(struct SBlasterProjectile* /*bp*/);
CImpactApplication* m_application = nullptr;
Ogre::SceneNode* m_shipNode = nullptr;
Ogre::SceneNode* m_targetingNode = nullptr;
Ogre::SceneNode* m_projectilesNode = nullptr;
CSSVEPFlickeringObject* m_shipCannon = nullptr;
CSSVEPFlickeringObject* m_shipLeftWing = nullptr;
CSSVEPFlickeringObject* m_shipRightWing = nullptr;
ETargetState m_targetStates[3];
int m_prepareAnimationFrame = 0;
bool m_targetLocked = true;
bool m_returning = false;
std::deque<size_t> m_nextEnemyPosition;
bool m_pilotAssistActive = false;
bool m_targetLockdownActive = false;
bool m_feedbackActive = false;
bool m_focusPointActive = false;
bool m_cannonInhibited = false;
Ogre::Radian m_currentAngle;
int m_nCurrentDisplacement = 0;
int m_shootingCooldown = 0;
std::vector<struct SBlasterProjectile*> m_projectiles;
int m_nShot = 0;
Ogre::Real m_origin = 0.0;
Ogre::Real m_oldPosition = 0;
};
} // namespace SSVEPMindShooter
} // namespace OpenViBE
@@ -0,0 +1,103 @@
#if defined(TARGET_HAS_ThirdPartyOgre3DTerrain)
#include "ovkCLogListenerFileBuffered.h"
#include <cstdio>
#include <iostream>
namespace OpenViBE {
namespace Kernel {
CLogListenerFileBuffered::CLogListenerFileBuffered(const IKernelContext& /*context*/, const CString& applicationName, const CString& logFilename)
: m_applicationName(applicationName), m_logFilename(logFilename)
{
m_f = fopen(m_logFilename.toASCIIString(), "wt");
if (m_f == nullptr)
{
std::cout << "[ ERROR ] Unable to open [" << m_logFilename << "] for writing. This log listener can not be initialized, it will do nothing!" << std::endl;
}
}
CLogListenerFileBuffered::~CLogListenerFileBuffered() { if (m_f != nullptr) { fclose(m_f); } }
bool CLogListenerFileBuffered::isActive(const ELogLevel level)
{
const auto it = m_activeLevels.find(level);
if (it == m_activeLevels.end()) { return true; }
return it->second;
}
bool CLogListenerFileBuffered::activate(const ELogLevel level, const bool active)
{
m_activeLevels[level] = active;
return true;
}
bool CLogListenerFileBuffered::activate(const ELogLevel startLevel, const ELogLevel endLevel, const bool active)
{
for (int i = startLevel; i <= endLevel; ++i) { m_activeLevels[ELogLevel(i)] = active; }
return true;
}
bool CLogListenerFileBuffered::activate(const bool active) { return activate(LogLevel_First, LogLevel_Last, active); }
void CLogListenerFileBuffered::log(const CTime value) { if (m_f != nullptr) { fprintf(m_f, "%llu", value.time()); } }
void CLogListenerFileBuffered::log(const uint64_t value) { if (m_f != nullptr) { fprintf(m_f, "%llu", value); } }
void CLogListenerFileBuffered::log(const uint32_t value) { if (m_f != nullptr) { fprintf(m_f, "%u", value); } }
void CLogListenerFileBuffered::log(const int64_t value) { if (m_f != nullptr) { fprintf(m_f, "%lli", value); } }
void CLogListenerFileBuffered::log(const int value) { if (m_f != nullptr) { fprintf(m_f, "%i", value); } }
void CLogListenerFileBuffered::log(const double value) { if (m_f != nullptr) { fprintf(m_f, "%lf", value); } }
void CLogListenerFileBuffered::log(const bool value) { if (m_f != nullptr) { fprintf(m_f, "%s", (value ? "true" : "false")); } }
void CLogListenerFileBuffered::log(const CIdentifier& value) { if (m_f != nullptr) { fprintf(m_f, "%s", value.str().c_str()); } }
void CLogListenerFileBuffered::log(const CString& value) { if (m_f != nullptr) { fprintf(m_f, "%s", value.toASCIIString()); } }
void CLogListenerFileBuffered::log(const std::string& value) { if (m_f != nullptr) { fprintf(m_f, "%s", value.c_str()); } }
void CLogListenerFileBuffered::log(const char* value) { if (m_f != nullptr) { fprintf(m_f, "%s", value); } }
void CLogListenerFileBuffered::log(const ELogLevel level)
{
if (m_f != nullptr)
{
switch (level)
{
case LogLevel_Debug:
fprintf(m_f, "[ DEBUG ] ");
break;
case LogLevel_Benchmark:
fprintf(m_f, "[ BENCH ] ");
break;
case LogLevel_Trace:
fprintf(m_f, "[ TRACE ] ");
break;
case LogLevel_Info:
fprintf(m_f, "[ INF ] ");
break;
case LogLevel_Warning:
fprintf(m_f, "[WARNING] ");
break;
case LogLevel_ImportantWarning:
fprintf(m_f, "[WARNING] ");
break;
case LogLevel_Error:
fprintf(m_f, "[ ERROR ] ");
break;
case LogLevel_Fatal:
fprintf(m_f, "[ FATAL ] ");
break;
default:
fprintf(m_f, "[UNKNOWN] ");
break;
}
}
}
} // namespace Kernel
} // namespace OpenViBE
#endif
@@ -0,0 +1,56 @@
#pragma once
#include <openvibe/ov_all.h>
#include <toolkit/ovtk_all.h>
#include <map>
#include <cstdio>
#define OVK_ClassId_Kernel_Log_LogListenerFileBuffered OpenViBE::CIdentifier(0x0FD252FB, 0x315C1A97)
namespace OpenViBE {
namespace Kernel {
class CLogListenerFileBuffered final : public ILogListener
{
public:
CLogListenerFileBuffered(const IKernelContext& context, const CString& applicationName, const CString& logFilename);
~CLogListenerFileBuffered() override;
bool isActive(const ELogLevel level) override;
bool activate(const ELogLevel level, const bool active) override;
bool activate(const ELogLevel startLevel, const ELogLevel endLevel, const bool active) override;
bool activate(const bool active) override;
void log(const CTime value) override;
void log(const uint64_t value) override;
void log(const uint32_t value) override;
void log(const int64_t value) override;
void log(const int value) override;
void log(const double value) override;
void log(const bool value) override;
void log(const CIdentifier& value) override;
void log(const CString& value) override;
void log(const std::string& value) override;
void log(const char* value) override;
void log(const ELogLevel level) override;
void log(const ELogColor /*color*/) override {}
_IsDerivedFromClass_Final_(ILogListener, OVK_ClassId_Kernel_Log_LogListenerFileBuffered)
protected:
std::map<ELogLevel, bool> m_activeLevels;
CString m_applicationName;
CString m_logFilename;
FILE* m_f = nullptr;
};
} // namespace Kernel
} // namespace OpenViBE
@@ -0,0 +1,378 @@
#if defined(TARGET_HAS_ThirdPartyOgre3DTerrain)
#include "ovamsCApplication.h"
#include <cmath>
#include <algorithm>
#include "fs/Files.h"
namespace OpenViBE {
namespace SSVEPMindShooter {
CApplication::~CApplication()
{
delete m_StimulusSender;
if (m_painter != nullptr)
{
(*m_logManager) << Kernel::LogLevel_Debug << "- m_painter\n";
delete m_painter;
m_painter = nullptr;
}
for (auto it = m_commands.begin();
it != m_commands.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* configManager = &(m_kernelCtx->getConfigurationManager());
(*m_logManager) << Kernel::LogLevel_Debug << " * CApplication::setup()\n";
// Plugin config path setup
Ogre::String pluginsPath;
#if defined TARGET_OS_Windows
#if defined TARGET_BUILDTYPE_Debug
pluginsPath = std::string(getenv("OGRE_HOME")) + std::string("/bin/debug/plugins_d.cfg");
#else
pluginsPath = std::string(getenv("OGRE_HOME")) + std::string("/bin/release/plugins.cfg");
#endif
#elif defined TARGET_OS_Linux
pluginsPath = std::string(configManager->expand("${Path_Data}/openvibe-ogre-plugins.cfg").toASCIIString());
#else
#error "No OS defined."
#endif
// Create LogManager to stop Ogre flooding the console and creating random files
(*m_logManager) << Kernel::LogLevel_Debug << "+ Creating Ogre logmanager\n";
Ogre::LogManager* logManager = new Ogre::LogManager();
(*m_logManager) << Kernel::LogLevel_Info << "Log level: " << configManager->expand("${Kernel_ConsoleLogLevel}") << "\n";
(*m_logManager) << Kernel::LogLevel_Info << "Application will output Ogre console log : " << configManager->expandAsBoolean(
"${SSVEP_Ogre_LogToConsole}", false) << "\n";
const CString ogreLog = configManager->expand("${SSVEP_UserDataFolder}/mind-shooter-[$core{date}-$core{time}]-ogre.log");
(*m_logManager) << Kernel::LogLevel_Info << "Ogre log file : " << ogreLog << "\n";
FS::Files::createParentPath(ogreLog);
logManager->createLog(ogreLog.toASCIIString(), true, configManager->expandAsBoolean("${SSVEP_Ogre_LogToConsole}", false), false);
// Root creation
const CString ogreCfg = configManager->expand("${SSVEP_MindShooterScenarioPath}") + "/appconf/mind-shooter-ogre.conf";
(*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, ogreCfg.toASCIIString(), ogreLog.toASCIIString());
// Resource handling
this->setupResources();
// Configuration from file or dialog window if needed
if (!this->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";
const int width = int(configManager->expandAsInteger("${SSVEP_Ogre_ScreenWidth}", 800));
const int height = int(configManager->expandAsInteger("${SSVEP_Ogre_ScreenHeight}", 600));
const bool fullScreen = configManager->expandAsBoolean("${SSVEP_Ogre_FullScreen}", false);
(*m_logManager) << Kernel::LogLevel_Info << "Width : " << width << " Height : " << height << " Fullscreen : " << fullScreen << "\n";
//m_window = m_root->createRenderWindow("SSVEP Stimulator", 960, 600, false, &l_oOptionList);
m_window = m_root->createRenderWindow("SSVEP Stimulator", width, height, fullScreen, &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");
m_cameraNode = m_sceneManager->getRootSceneNode()->createChildSceneNode();
m_cameraNode->attachObject(m_camera);
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(configManager->expand("${SSVEP_UserDataFolder}/mind-shooter-[$core{date}-$core{time}]-cegui.log"));
(*m_logManager) << Kernel::LogLevel_Debug << " * CEGUI initialized\n";
// create the vector of stimulation frequencies
m_screenRefreshRate = double(configManager->expandAsUInteger("${SSVEP_ScreenRefreshRate}", 60));
(*m_logManager) << Kernel::LogLevel_Info << "Specified screen refresh rate :" << m_screenRefreshRate << "Hz\n";
if (m_screenRefreshRate > 64)
{
(*m_logManager) << Kernel::LogLevel_Error << "Screen refresh rate exceeds the max bit pattern length of 64\n";
return false;
}
size_t i = 1;
CIdentifier frequencyId = configManager->createConfigurationToken("SSVEP_FrequencyId", "1");
m_frequencies.push_back(30);
size_t patternsLoaded = 0;
// TODO: Load patterns
// Load pre-defined stimulation patterns (binary encoded dark/light frames inside a 64bit integer)
while (configManager->lookUpConfigurationTokenIdentifier(configManager->expand("SSVEP_Pattern_${SSVEP_FrequencyId}")) !=
CIdentifier::undefined())
{
size_t stimulationPattern = size_t(configManager->expandAsInteger("${SSVEP_Pattern_${SSVEP_FrequencyId}}"));
(*m_logManager) << Kernel::LogLevel_Info << "Pattern number " << i << " pattern : " << stimulationPattern << "\n";
m_frequencies[i] = stimulationPattern;
configManager->releaseConfigurationToken(frequencyId);
frequencyId = configManager->createConfigurationToken("SSVEP_FrequencyId", std::to_string(++i).c_str());
patternsLoaded++;
}
// Generate patterns from frequencies
if (patternsLoaded == 0)
{
// Load frequencies
while (configManager->lookUpConfigurationTokenIdentifier(configManager->expand("SSVEP_Frequency_${SSVEP_FrequencyId}")) != CIdentifier::undefined())
{
const double currentFrequency = double(configManager->expandAsFloat("${SSVEP_Frequency_${SSVEP_FrequencyId}}"));
const double approximatedFrameCount = m_screenRefreshRate / currentFrequency;
const size_t nRoundedFrame = size_t(floor(approximatedFrameCount + 0.5));
// test if the desired frequency can be reasonably created on the screen
if (fabs(approximatedFrameCount - nRoundedFrame) < 0.003)
{
const size_t framesL = nRoundedFrame / 2 + nRoundedFrame % 2;
const size_t framesD = nRoundedFrame / 2;
// the pattern is procedurally generated and always starts by a 1,
// following by as many 0s as there are Dark frames and finally as many 1s as there are Light frames.
// The frame loop will consume one bit per frame from the right and then reset when the reset marker is hit.
// Start with the reset marker
uint64_t stimulationPattern = 1;
// The dark zeroes
stimulationPattern <<= framesD;
// The light ones
for (size_t j = 0; j < framesL; ++j)
{
stimulationPattern <<= 1;
stimulationPattern += 1;
}
(*m_logManager) << Kernel::LogLevel_Info << "Frequency number " << i << ": " << currentFrequency << "Hz / " <<
floor(approximatedFrameCount + 0.5) << " ( " << framesL << " light, " << framesD << " dark) frames @ " <<
m_screenRefreshRate << "fps\n";
(*m_logManager) << Kernel::LogLevel_Info << "Frequency number " << i << " pattern : " << stimulationPattern << "\n";
std::stringstream binary;
binary << std::bitset<64>(stimulationPattern);
(*m_logManager) << Kernel::LogLevel_Info << "Frequency number " << i << " binary : " << binary.str() << "\n";
m_frequencies.push_back(stimulationPattern);
patternsLoaded++;
}
else { (*m_logManager) << Kernel::LogLevel_Error << "The selected frequency (" << currentFrequency << "Hz) is not supported by your screen.\n"; }
configManager->releaseConfigurationToken(frequencyId);
frequencyId = configManager->createConfigurationToken("SSVEP_FrequencyId", std::to_string(++i).c_str());
}
}
if (!patternsLoaded)
{
(*m_logManager) << Kernel::LogLevel_Error << "No flashing frequencies loaded. Have you run the SSVEP Impact Shooter configuring scenario?\n";
(*m_logManager) << Kernel::LogLevel_Error << "Are you running this app from the correct scenario with the previous stages run properly?\n";
return false;
}
m_StimulusSender->connect("localhost", "15361");
return true;
}
// Set hard-coded parameters, VSync in particular, for all known render systems
void CApplication::setOgreParameters() const
{
const bool fullScreen = m_kernelCtx->getConfigurationManager().expandAsBoolean("${SSVEP_Ogre_FullScreen}", false);
const Ogre::RenderSystemList& list = m_root->getAvailableRenderers();
for (size_t i = 0; i < list.size(); ++i)
{
list[i]->setConfigOption("VSync", "Yes");
list[i]->setConfigOption("Full Screen", (fullScreen ? "Yes" : "No"));
}
}
bool CApplication::configure() const
{
if (! m_root->restoreConfig())
{
setOgreParameters();
if (! m_root->showConfigDialog())
{
(*m_logManager) << Kernel::LogLevel_Error << "No configuration created from the dialog window.\n";
return false;
}
}
// Override 'unsuitable' user choices
(*m_logManager) << Kernel::LogLevel_Info << "Forcing vsync and using fullscreen settings from configuration scenario.\n";
setOgreParameters();
// Save the config again after we have forced the params, otherwise the conf file looks misleading
m_root->saveConfig();
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_guiRenderer = &(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((CEGUI::utf8*)"TaharezLook-ov.scheme");
#endif
(*m_logManager) << Kernel::LogLevel_Debug << "+ Creating CEGUI WindowManager\n";
m_guiWindowManager = CEGUI::WindowManager::getSingletonPtr();
m_sheet = m_guiWindowManager->createWindow("DefaultWindow", "RootSheet");
(*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() const
{
(*m_logManager) << Kernel::LogLevel_Trace << "Creating a new viewport\n";
const Ogre::uint32 viewportSize = std::min(m_windowWidth, m_windowHeight);
(*m_logManager) << Kernel::LogLevel_Info << "New viewport size : " << viewportSize << "\n";
m_viewport->setDimensions(Ogre::Real(m_windowWidth - viewportSize) / Ogre::Real(m_windowWidth) / 2,
Ogre::Real(m_windowHeight - viewportSize) / Ogre::Real(m_windowHeight) / 2,
Ogre::Real(viewportSize) / Ogre::Real(m_windowWidth),
Ogre::Real(viewportSize) / Ogre::Real(m_windowHeight));
}
void CApplication::setupResources() const
{
Kernel::IConfigurationManager* configManager = &(m_kernelCtx->getConfigurationManager());
Ogre::ResourceGroupManager::getSingleton().addResourceLocation(
configManager->expand("${Path_Data}/applications/${SSVEP_MindShooterFolderName}/resources").toASCIIString(), "FileSystem", "SSVEP");
Ogre::ResourceGroupManager::getSingleton().addResourceLocation(
configManager->expand("${Path_Data}/applications/${SSVEP_MindShooterFolderName}/resources/generic").toASCIIString(), "FileSystem", "SSVEPGeneric");
Ogre::ResourceGroupManager::getSingleton().addResourceLocation(
configManager->expand("${Path_Data}/applications/${SSVEP_MindShooterFolderName}/resources/generic/textures").toASCIIString(), "FileSystem",
"SSVEPGeneric");
Ogre::ResourceGroupManager::getSingleton().addResourceLocation(
configManager->expand("${Path_Data}/applications/${SSVEP_MindShooterFolderName}/resources/trainer").toASCIIString(), "FileSystem", "SSVEPTrainer");
Ogre::ResourceGroupManager::getSingleton().addResourceLocation(
configManager->expand("${Path_Data}/applications/${SSVEP_MindShooterFolderName}/resources/gui").toASCIIString(), "FileSystem", "CEGUI");
Ogre::ResourceGroupManager::getSingleton().addResourceLocation(CString(m_ScenarioDir + "/appconf/materials").toASCIIString(), "FileSystem", "CEGUI");
Ogre::ResourceGroupManager::getSingleton().initialiseResourceGroup("SSVEP");
Ogre::ResourceGroupManager::getSingleton().initialiseResourceGroup("SSVEPTrainer");
Ogre::ResourceGroupManager::getSingleton().initialiseResourceGroup("SSVEPGeneric");
Ogre::ResourceGroupManager::getSingleton().initialiseResourceGroup("CEGUI");
}
bool CApplication::frameStarted(const Ogre::FrameEvent& /*evt*/)
{
m_currentFrame++;
m_currentFrame %= int(m_screenRefreshRate);
for (size_t i = 0; i < m_commands.size(); ++i) { m_commands[i]->processFrame(); }
this->processFrame(m_currentFrame);
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 SSVEPMindShooter
} // namespace OpenViBE
#endif
@@ -0,0 +1,114 @@
#pragma once
#include "ovams_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 "ovamsICommand.h"
#include "ovamsCBasicPainter.h"
#include <tcptagging/IStimulusSender.h>
namespace OpenViBE {
namespace SSVEPMindShooter {
class CApplication : public Ogre::FrameListener, public Ogre::WindowEventListener
{
public:
explicit CApplication(const CString& scenarioDir) : m_ScenarioDir(scenarioDir) { m_StimulusSender = TCPTagging::CreateStimulusSender(); }
~CApplication() override;
void addCommand(ICommand* cmd) { m_commands.push_back(cmd); }
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() { }
virtual void debugAction1() { }
virtual void debugAction2() { }
virtual void debugAction3() { }
virtual void debugAction4() { }
virtual void setTarget(int /*i*/) { }
Ogre::RenderWindow* getWindow() const { return m_window; }
Ogre::SceneManager* getSceneManager() const { return m_sceneManager; }
Ogre::SceneNode* getSceneNode() const { return m_sceneNode; }
Ogre::Camera* getCamera() const { return m_camera; }
Ogre::SceneNode* getCameraNode() const { return m_cameraNode; }
CBasicPainter* getPainter() const { return m_painter; }
Kernel::ILogManager& getLogManager() const { return (*m_logManager); }
Kernel::IConfigurationManager* getConfigurationManager() const { return &(m_kernelCtx->getConfigurationManager()); }
std::vector<size_t>* getFrequencies() { return &m_frequencies; }
void exit() { m_continueRendering = false; }
void resizeViewport() const;
Kernel::ILogManager& logPrefix() const
{
(*m_logManager) << Kernel::LogLevel_Trace << "% [" << m_currentTime << "] ";
return (*m_logManager);
}
CString m_ScenarioDir;
TCPTagging::IStimulusSender* m_StimulusSender = nullptr;
protected:
Kernel::IKernelContext* m_kernelCtx = nullptr;
Kernel::ILogManager* m_logManager = nullptr;
double m_screenRefreshRate = 0;
CBasicPainter* m_painter = nullptr;
bool m_continueRendering = true;
size_t m_currentFrame = 0;
uint64_t m_currentTime = 0;
Ogre::Root* m_root = nullptr;
Ogre::SceneManager* m_sceneManager = nullptr;
Ogre::Camera* m_camera = nullptr;
Ogre::SceneNode* m_cameraNode = nullptr;
Ogre::RenderWindow* m_window = nullptr;
Ogre::Viewport* m_viewport = nullptr;
Ogre::SceneNode* m_sceneNode = nullptr;
CEGUI::OgreRenderer* m_guiRenderer = nullptr;
CEGUI::WindowManager* m_guiWindowManager = nullptr;
CEGUI::Window* m_sheet = nullptr;
std::vector<size_t> m_frequencies;
std::vector<ICommand*> m_commands;
virtual void processFrame(const size_t /*currentFrame*/) { m_currentTime++; }
bool frameRenderingQueued(const Ogre::FrameEvent& evt) override { return (m_continueRendering && !m_window->isClosed()); }
bool frameStarted(const Ogre::FrameEvent& evt) override;
bool configure() const;
void setupResources() const;
private:
void setOgreParameters() const; // Set some render parameters
void initCEGUI(const char* logFilename);
Ogre::uint32 m_windowWidth = 0;
Ogre::uint32 m_windowHeight = 0;
};
} // namespace SSVEPMindShooter
} // namespace OpenViBE
@@ -0,0 +1,248 @@
#if defined(TARGET_HAS_ThirdPartyOgre3DTerrain)
#include "ovamsCBasicPainter.h"
#include "ovamsCApplication.h"
#if (OGRE_VERSION_MAJOR > 1) || ((OGRE_VERSION_MAJOR == 1) && (OGRE_VERSION_MINOR >= 9))
#include "Overlay/OgreOverlaySystem.h"
#include "Overlay/OgreOverlayContainer.h"
#include "Overlay/OgreOverlayElement.h"
#endif
namespace OpenViBE {
namespace SSVEPMindShooter {
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::paintTexturedRectangle(const Ogre::RealRect& oRectangle, const Ogre::String& sSurface, const int plane) const
{
Ogre::ManualObject* object = m_sceneManager->createManualObject();
object->begin(sSurface, Ogre::RenderOperation::OT_TRIANGLE_FAN);
object->setUseIdentityProjection(true);
object->setUseIdentityView(true);
object->position(oRectangle.right, oRectangle.top, 0.0);
object->textureCoord(0, 0);
object->index(0);
object->position(oRectangle.left, oRectangle.top, 0.0);
object->textureCoord(1, 0);
object->index(1);
object->position(oRectangle.left, oRectangle.bottom, 0.0);
object->textureCoord(1, 1);
object->index(2);
object->position(oRectangle.right, oRectangle.bottom, 0.0);
object->textureCoord(0, 1);
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 Ogre::Vector2 p1, const Ogre::Vector2 p2, const Ogre::Vector2 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.x, p1.y, 0.0);
object->colour(color);
object->index(0);
object->position(p2.x, p2.y, 0.0);
object->colour(color);
object->index(1);
object->position(p3.x, p3.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::paintTriangle(const Ogre::Vector3 p1, const Ogre::Vector3 p2, const Ogre::Vector3 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.x, p1.y, p1.z);
object->colour(color);
object->index(0);
object->position(p2.x, p2.y, p2.z);
object->colour(color);
object->index(1);
object->position(p3.x, p3.y, p3.z);
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;
}
Ogre::ManualObject* CBasicPainter::beginPainingPolygon(bool /*filled*/, const Ogre::String& material) const
{
Ogre::ManualObject* object = m_sceneManager->createManualObject();
object->begin(material, Ogre::RenderOperation::OT_TRIANGLE_FAN);
object->setUseIdentityProjection(true);
object->setUseIdentityView(true);
return object;
}
void CBasicPainter::addPointToPolygon(Ogre::ManualObject* pPolygon, const Ogre::Real rX, const Ogre::Real rY, const Ogre::ColourValue color)
{
pPolygon->position(rX, rY, 0.0);
pPolygon->colour(color);
}
void CBasicPainter::finishPaintingPolygon(Ogre::ManualObject* pPolygon, const int plane) const
{
pPolygon->end();
pPolygon->setBoundingBox(m_aabInf);
pPolygon->setRenderQueueGroup(Ogre::RENDER_QUEUE_OVERLAY - plane);
pPolygon->setVisible(true);
}
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);
}
} // namespace SSVEPMindShooter
} // namespace OpenViBE
#endif
@@ -0,0 +1,50 @@
#pragma once
/// this class is a wrapper around some ogre methods to display basic shapes
#include <Ogre.h>
#if (OGRE_VERSION_MAJOR > 1) || ((OGRE_VERSION_MAJOR == 1) && (OGRE_VERSION_MINOR >= 9))
#include "Overlay/OgreOverlayManager.h"
#endif
#define SSVEP_DEFAULT_COLOUR Ogre::ColourValue(1.0f, 1.0f, 1.0f)
namespace OpenViBE {
namespace SSVEPMindShooter {
class CApplication;
class CBasicPainter
{
public:
explicit CBasicPainter(CApplication* application);
~CBasicPainter() {}
Ogre::SceneManager* getSceneManager() const { return m_sceneManager; }
Ogre::ManualObject* paintRectangle(const Ogre::RealRect& oRectangle, const Ogre::ColourValue color = SSVEP_DEFAULT_COLOUR, const int plane = 1) const;
Ogre::ManualObject* paintTexturedRectangle(const Ogre::RealRect& oRectangle, const Ogre::String& sSurface, const int plane = 1) const;
Ogre::ManualObject* paintTriangle(Ogre::Vector2 p1, Ogre::Vector2 p2, Ogre::Vector2 p3, Ogre::ColourValue color = SSVEP_DEFAULT_COLOUR,
int plane = 1) const;
Ogre::ManualObject* paintTriangle(Ogre::Vector3 p1, Ogre::Vector3 p2, Ogre::Vector3 p3, Ogre::ColourValue color = SSVEP_DEFAULT_COLOUR,
int plane = 1) const;
//Ogre::ManualObject* paintTexturedTriangle(Ogre::Vector2 p1, Ogre::Vector2 p2, Ogre::Vector2 p3, Ogre::String sSurface, int plane = 1);
Ogre::ManualObject* paintCircle(Ogre::Real rX, Ogre::Real rY, Ogre::Real rR, Ogre::ColourValue color = SSVEP_DEFAULT_COLOUR, bool bFilled = true,
int plane = 1) const;
Ogre::ManualObject* beginPainingPolygon(bool filled = true, const Ogre::String& material = "BasicSurface/Diffuse") const;
static void addPointToPolygon(Ogre::ManualObject* pPolygon, Ogre::Real rX, Ogre::Real rY, Ogre::ColourValue color = SSVEP_DEFAULT_COLOUR);
void finishPaintingPolygon(Ogre::ManualObject* pPolygon, int plane = 1) const;
void paintText(const std::string& sID, const std::string& sText, Ogre::Real rX, Ogre::Real rY, Ogre::Real rWidth, 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 SSVEPMindShooter
} // namespace OpenViBE
@@ -0,0 +1,96 @@
#if defined(TARGET_HAS_ThirdPartyOgre3DTerrain)
#include "ovamsCCommandCamera.h"
#include "ovamsCApplication.h"
#include "ovamsCVRPNServer.h"
namespace OpenViBE {
namespace SSVEPMindShooter {
void CCommandCamera::updateCamera()
{
Ogre::Vector3 translation(0, 0, 0);
const Ogre::Real translationSpeed = 10.0;
if (m_keysPressed[OIS::KC_W]) { translation.z -= translationSpeed; }
if (m_keysPressed[OIS::KC_D]) { translation.x += translationSpeed; }
if (m_keysPressed[OIS::KC_A]) { translation.x -= translationSpeed; }
if (m_keysPressed[OIS::KC_S]) { translation.z += translationSpeed; }
const Ogre::Vector3 translateVectorFinal = m_application->getCamera()->getDerivedOrientation() * translation;
m_application->getCameraNode()->translate(translateVectorFinal, Ogre::Node::TS_WORLD);
}
void CCommandCamera::processFrame()
{
ICommandOIS::processFrame();
this->updateCamera();
if (m_keysPressed[OIS::KC_NUMPAD1])
{
m_application->debugAction1();
m_keysPressed[OIS::KC_NUMPAD1] = false;
}
if (m_keysPressed[OIS::KC_NUMPAD2])
{
m_application->debugAction2();
m_keysPressed[OIS::KC_NUMPAD2] = false;
}
if (m_keysPressed[OIS::KC_NUMPAD3])
{
m_application->debugAction3();
m_keysPressed[OIS::KC_NUMPAD3] = false;
}
if (m_keysPressed[OIS::KC_NUMPAD4])
{
m_application->debugAction4();
m_keysPressed[OIS::KC_NUMPAD4] = false;
}
}
void CCommandCamera::receiveKeyPressedEvent(const OIS::KeyCode key)
{
if (key == OIS::KC_LCONTROL) { m_bCameraMode = true; }
if (key == OIS::KC_W) { m_keysPressed[OIS::KC_W] = true; }
if (key == OIS::KC_A) { m_keysPressed[OIS::KC_A] = true; }
if (key == OIS::KC_S) { m_keysPressed[OIS::KC_S] = true; }
if (key == OIS::KC_D) { m_keysPressed[OIS::KC_D] = true; }
if (key == OIS::KC_NUMPAD1) { m_keysPressed[OIS::KC_NUMPAD1] = true; }
if (key == OIS::KC_NUMPAD2) { m_keysPressed[OIS::KC_NUMPAD2] = true; }
if (key == OIS::KC_NUMPAD3) { m_keysPressed[OIS::KC_NUMPAD3] = true; }
if (key == OIS::KC_NUMPAD4) { m_keysPressed[OIS::KC_NUMPAD4] = true; }
if (key == OIS::KC_ESCAPE) { m_application->exit(); }
}
void CCommandCamera::receiveKeyReleasedEvent(const OIS::KeyCode key)
{
if (key == OIS::KC_LCONTROL) { m_bCameraMode = false; }
if (key == OIS::KC_W) { m_keysPressed[OIS::KC_W] = false; }
if (key == OIS::KC_A) { m_keysPressed[OIS::KC_A] = false; }
if (key == OIS::KC_S) { m_keysPressed[OIS::KC_S] = false; }
if (key == OIS::KC_D) { m_keysPressed[OIS::KC_D] = false; }
if (key == OIS::KC_NUMPAD1) { m_keysPressed[OIS::KC_NUMPAD1] = false; }
if (key == OIS::KC_NUMPAD2) { m_keysPressed[OIS::KC_NUMPAD2] = false; }
if (key == OIS::KC_NUMPAD3) { m_keysPressed[OIS::KC_NUMPAD3] = false; }
if (key == OIS::KC_NUMPAD4) { m_keysPressed[OIS::KC_NUMPAD4] = false; }
}
void CCommandCamera::receiveMouseEvent(const OIS::MouseEvent& event)
{
const Ogre::Real rotationSpeedMouse = 1.0F;
std::cout << m_application->getCamera()->getOrientation() << "\n";
if (m_bCameraMode)
{
m_application->getCamera()->yaw(Ogre::Degree(-float(event.state.X.rel) * rotationSpeedMouse));
m_application->getCamera()->pitch(Ogre::Degree(-float(event.state.Y.rel) * rotationSpeedMouse));
}
}
} // namespace SSVEPMindShooter
} // namespace OpenViBE
#endif
@@ -0,0 +1,29 @@
#pragma once
#include <map>
#include "ovamsICommandOIS.h"
namespace OpenViBE {
namespace SSVEPMindShooter {
class CVRPNServer;
class CCommandCamera final : public ICommandOIS
{
public:
explicit CCommandCamera(CApplication* application): ICommandOIS(application) { }
~CCommandCamera() override { }
void processFrame() override;
void receiveKeyPressedEvent(OIS::KeyCode key) override;
void receiveKeyReleasedEvent(OIS::KeyCode key) override;
void receiveMouseEvent(const OIS::MouseEvent& event) override;
private:
void updateCamera();
std::map<OIS::KeyCode, bool> m_keysPressed;
bool m_bCameraMode = false;
};
} // namespace SSVEPMindShooter
} // namespace OpenViBE
@@ -0,0 +1,19 @@
#pragma once
#include "ovamsICommandVRPNButton.h"
#include "ovamsCApplication.h"
namespace OpenViBE {
namespace SSVEPMindShooter {
class CApplication;
class CCommandReceiveTarget final : public ICommandVRPNButton
{
public:
explicit CCommandReceiveTarget(CApplication* application) : ICommandVRPNButton(application, "SSVEP_VRPN_TargetControl") {}
~CCommandReceiveTarget() override {}
void execute(const int button, const int state) override { dynamic_cast<CApplication*>(m_application)->setTarget(button); }
};
} // namespace SSVEPMindShooter
} // namespace OpenViBE
@@ -0,0 +1,49 @@
#if defined(TARGET_HAS_ThirdPartyOgre3DTerrain)
#include "ovamsCCommandStartStop.h"
#include "ovamsCApplication.h"
#include "ovamsCVRPNServer.h"
namespace OpenViBE {
namespace SSVEPMindShooter {
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(); }
if (key == OIS::KC_INSERT) { m_application->getWindow()->writeContentsToFile("screenshot.png"); }
}
void CCommandStartStop::receiveKeyReleasedEvent(const OIS::KeyCode key)
{
if (key == OIS::KC_SPACE) { m_vrpnServer->changeButtonState("SSVEP_VRPN_StartStop", 0, 0); }
}
} // namespace SSVEPMindShooter
} // namespace OpenViBE
#endif
@@ -0,0 +1,24 @@
#pragma once
#include "ovamsICommandOIS.h"
namespace OpenViBE {
namespace SSVEPMindShooter {
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 SSVEPMindShooter
} // namespace OpenViBE
@@ -0,0 +1,45 @@
#if defined(TARGET_HAS_ThirdPartyOgre3DTerrain)
#include "ovamsCCommandStimulatorControl.h"
#include "ovamsCApplication.h"
#include <toolkit/ovtk_stimulations.h>
namespace OpenViBE {
namespace SSVEPMindShooter {
void CCommandStimulatorControl::execute(const int button, const int /*state*/)
{
// only run the commands once, skip
switch (button)
{
case 0:
m_application->startExperiment();
m_application->m_StimulusSender->sendStimulation(OVTK_StimulationId_ExperimentStart);
break;
case 1:
m_application->stopExperiment();
m_application->m_StimulusSender->sendStimulation(OVTK_StimulationId_ExperimentStop);
break;
case 2:
m_application->startFlickering();
m_application->m_StimulusSender->sendStimulation(OVTK_StimulationId_VisualStimulationStart);
break;
case 3:
m_application->stopFlickering();
m_application->m_StimulusSender->sendStimulation(OVTK_StimulationId_VisualStimulationStop);
break;
default:
m_application->getLogManager() << Kernel::LogLevel_Error << "[ERROR] Unknown command\n";
break;
}
}
} // namespace SSVEPMindShooter
} // namespace OpenViBE
#endif
@@ -0,0 +1,16 @@
#pragma once
#include "ovamsICommandVRPNButton.h"
namespace OpenViBE {
namespace SSVEPMindShooter {
class CCommandStimulatorControl final : public ICommandVRPNButton
{
public:
explicit CCommandStimulatorControl(CApplication* application) : ICommandVRPNButton(application, "SSVEP_VRPN_StimulatorControl") {}
~CCommandStimulatorControl() override { }
void execute(const int button, const int state) override;
};
} // namespace SSVEPMindShooter
} // namespace OpenViBE
@@ -0,0 +1,35 @@
#if defined(TARGET_HAS_ThirdPartyOgre3DTerrain)
#include "ovamsCSSVEPFlickeringObject.h"
namespace OpenViBE {
namespace SSVEPMindShooter {
CSSVEPFlickeringObject::CSSVEPFlickeringObject(Ogre::SceneNode* objectNode, const uint64_t stimulationPattern)
: m_objectNode(objectNode), m_stimulationPattern(stimulationPattern)
{
static int nextid = 0;
m_iId = ++nextid;
}
void CSSVEPFlickeringObject::setVisible(const bool visibility)
{
if ((!m_visible && visibility) || (m_visible && !visibility)) { m_objectNode->flipVisibility(); }
m_visible = visibility;
}
void CSSVEPFlickeringObject::processFrame()
{
// If the bit for the frame is '1', set to visible
if (((m_stimulationPattern >> m_currentFrame) % 2) == 1) { this->setVisible(true); }
else { this->setVisible(false); }
m_currentFrame++;
// Start over when only '1' is left
if (m_stimulationPattern >> m_currentFrame == 1) { m_currentFrame = 0; }
}
} // namespace SSVEPMindShooter
} // namespace OpenViBE
#endif
@@ -0,0 +1,32 @@
#pragma once
#include <openvibe/ov_all.h>
#include <toolkit/ovtk_all.h>
#include <Ogre.h>
namespace OpenViBE {
namespace SSVEPMindShooter {
class CSSVEPFlickeringObject
{
public:
//SP CSSVEPFlickeringObject( Ogre::SceneNode* objectNode, size_t LitFrames, size_t DarkFrames );
CSSVEPFlickeringObject(Ogre::SceneNode* objectNode, uint64_t stimulationPattern);
virtual ~CSSVEPFlickeringObject() { }
virtual void setVisible(bool visibility);
virtual void processFrame();
protected:
Ogre::SceneNode* m_objectNode = nullptr;
size_t m_currentFrame = 0;
//SP size_t m_litFrames = 0;
//SP size_t m_darkFrames = 0;
uint64_t m_stimulationPattern = 0;
private:
bool m_visible = true;
int m_iId = 0;
};
} // namespace SSVEPMindShooter
} // namespace OpenViBE
@@ -0,0 +1,52 @@
#if defined(TARGET_HAS_ThirdPartyOgre3DTerrain)
#include "ovamsCVRPNServer.h"
#include "ovamsCApplication.h"
#include <vrpn_Connection.h>
#include <vrpn_Button.h>
namespace OpenViBE {
namespace SSVEPMindShooter {
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 std::string& name, const int buttonCount)
{
m_oButtonServer.insert(std::pair<std::string, vrpn_Button_Server*>(name, new vrpn_Button_Server(name.c_str(), m_connection, buttonCount)));
m_oButtonCache[name].clear();
m_oButtonCache[name].resize(buttonCount);
}
void CVRPNServer::processFrame()
{
for (auto it = m_oButtonServer.begin(); it != m_oButtonServer.end(); ++it) { it->second->mainloop(); }
m_connection->mainloop();
}
void CVRPNServer::changeButtonState(const std::string& name, const int iIndex, const int state)
{
m_oButtonServer[name]->set_button(iIndex, state);
m_oButtonCache[name][iIndex] = state;
}
} // namespace SSVEPMindShooter
} // 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 SSVEPMindShooter {
class CApplication;
class CVRPNServer
{
public:
static CVRPNServer* getInstance(CApplication* application);
~CVRPNServer() = default;
void processFrame();
void addButton(const std::string& name, const int buttonCount);
void changeButtonState(const std::string& name, const int iIndex, const int state);
int getButtonState(const std::string& name, const int iIndex) { return m_oButtonCache[name][iIndex]; }
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_oButtonServer;
std::map<std::string, std::vector<int>> m_oButtonCache;
};
} // namespace SSVEPMindShooter
} // namespace OpenViBE
@@ -0,0 +1,21 @@
#pragma once
#include <openvibe/ov_all.h>
#include <toolkit/ovtk_all.h>
namespace OpenViBE {
namespace SSVEPMindShooter {
class CApplication;
class ICommand
{
public:
explicit ICommand(CApplication* application) : m_application(application) {}
virtual ~ICommand() {}
virtual void processFrame() = 0;
protected:
CApplication* m_application = nullptr;
};
} // namespace SSVEPMindShooter
} // namespace OpenViBE
@@ -0,0 +1,107 @@
#if defined(TARGET_HAS_ThirdPartyOgre3DTerrain)
#include "ovamsICommandOIS.h"
#include "ovamsCApplication.h"
#define SSVEP_NO_MOUSE_CAPTURE
namespace OpenViBE {
namespace SSVEPMindShooter {
OIS::InputManager* ICommandOIS::m_inputManager = nullptr;
OIS::Keyboard* ICommandOIS::m_keyboard = nullptr;
OIS::Mouse* ICommandOIS::m_mouse = 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);
#ifndef SSVEP_NO_MOUSE_CAPTURE
m_mouse = static_cast<OIS::Mouse*>(m_inputManager->createInputObject(OIS::OISMouse, true));
m_mouse->setEventCallback( this );
#endif
}
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;
#ifndef SSVEP_NO_MOUSE_CAPTURE
m_application->getLogManager() << Kernel::LogLevel_Debug << "- destroy m_mouse\n";
m_inputManager->destroyInputObject( m_mouse );
m_mouse = nullptr;
#endif
}
OIS::InputManager::destroyInputSystem(m_inputManager);
}
}
}
void ICommandOIS::processFrame()
{
m_keyboard->capture();
#ifndef SSVEP_NO_MOUSE_CAPTURE
m_mouse->capture();
#endif
}
bool ICommandOIS::keyPressed(const OIS::KeyEvent& oEvent)
{
for (size_t i = 0; i < m_instances.size(); ++i) { m_instances[i]->receiveKeyPressedEvent(oEvent.key); }
return true;
}
bool ICommandOIS::keyReleased(const OIS::KeyEvent& oEvent)
{
for (size_t i = 0; i < m_instances.size(); ++i) { m_instances[i]->receiveKeyReleasedEvent(oEvent.key); }
return true;
}
#ifndef SSVEP_NO_MOUSE_CAPTURE
bool ICommandOIS::mouseMoved(const OIS::MouseEvent & event)
{
for (size_t i = 0; i < m_instances.size(); ++i) { m_instances[i]->receiveMouseEvent(event); }
return true;
}
#endif
} // namespace SSVEPMindShooter
} // namespace OpenViBE
#endif
@@ -0,0 +1,41 @@
#pragma once
#include <vector>
#include <OIS.h>
#include <OISKeyboard.h>
#include <OISMouse.h>
#include "ovamsICommand.h"
namespace OpenViBE {
namespace SSVEPMindShooter {
class ICommandOIS : public ICommand, OIS::KeyListener, OIS::MouseListener
{
static std::vector<ICommandOIS*> m_instances;
static int m_nInstance;
protected:
static OIS::InputManager* m_inputManager;
static OIS::Keyboard* m_keyboard;
static OIS::Mouse* m_mouse;
public:
explicit ICommandOIS(CApplication* application);
~ICommandOIS() override;
void processFrame() override;
protected:
virtual void receiveKeyPressedEvent(OIS::KeyCode key) = 0;
virtual void receiveKeyReleasedEvent(OIS::KeyCode key) = 0;
virtual void receiveMouseEvent(const OIS::MouseEvent& /*oEvent*/) {}
private:
bool keyPressed(const OIS::KeyEvent& oEvent) override;
bool keyReleased(const OIS::KeyEvent& oEvent) override;
bool mouseMoved(const OIS::MouseEvent& event) override { return true; }
bool mousePressed(const OIS::MouseEvent& /*arg*/, OIS::MouseButtonID /*id*/) override { return true; }
bool mouseReleased(const OIS::MouseEvent& /*arg*/, OIS::MouseButtonID /*id*/) override { return true; }
};
} // namespace SSVEPMindShooter
} // namespace OpenViBE
@@ -0,0 +1,39 @@
#if defined(TARGET_HAS_ThirdPartyOgre3DTerrain)
#include "ovamsICommandVRPNAnalog.h"
#include "ovamsCApplication.h"
#include <vrpn_Connection.h>
#include <vrpn_Analog.h>
namespace OpenViBE {
namespace SSVEPMindShooter {
static void VRPN_CALLBACK ssvep_vrpn_callback_analog(void* command, vrpn_ANALOGCB analog)
{
static_cast<ICommandVRPNAnalog*>(command)->execute(analog.num_channel, analog.channel);
}
ICommandVRPNAnalog::ICommandVRPNAnalog(CApplication* application, const CString& name) : ICommand(application)
{
Kernel::IConfigurationManager* configManager = application->getConfigurationManager();
const std::string analogName = std::string(name.toASCIIString()) + "@" + (configManager->expand("${SSVEP_VRPNHost}")).toASCIIString();
m_application->getLogManager() << Kernel::LogLevel_Debug << "+ m_vrpnAnalog = new vrpn_Analog_Remote(" << analogName << ")\n";
m_vrpnAnalog = new vrpn_Analog_Remote(analogName.c_str());
m_vrpnAnalog->register_change_handler(static_cast<void*>(this), ssvep_vrpn_callback_analog);
}
ICommandVRPNAnalog::~ICommandVRPNAnalog()
{
m_application->getLogManager() << Kernel::LogLevel_Debug << "- delete m_vrpnAnalog\n";
delete m_vrpnAnalog;
}
void ICommandVRPNAnalog::processFrame() { m_vrpnAnalog->mainloop(); }
} // namespace SSVEPMindShooter
} // namespace OpenViBE
#endif
@@ -0,0 +1,23 @@
#pragma once
#include "ovamsICommand.h"
#include <array>
class vrpn_Analog_Remote;
namespace OpenViBE {
namespace SSVEPMindShooter {
class ICommandVRPNAnalog : public ICommand
{
public:
ICommandVRPNAnalog(CApplication* application, const CString& name);
~ICommandVRPNAnalog() override;
void processFrame() override;
virtual void execute(int channelCount, double* channel) = 0;
protected:
vrpn_Analog_Remote* m_vrpnAnalog = nullptr;
};
} // namespace SSVEPMindShooter
} // namespace OpenViBE
@@ -0,0 +1,41 @@
#if defined(TARGET_HAS_ThirdPartyOgre3DTerrain)
#include "ovamsICommandVRPNButton.h"
#include "ovamsCApplication.h"
#include <vrpn_Connection.h>
#include <vrpn_Button.h>
namespace OpenViBE {
namespace SSVEPMindShooter {
static void VRPN_CALLBACK ssvep_vrpn_callback_button(void* command, 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()) + std::string("@") + std::string(
(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 SSVEPMindShooter
} // namespace OpenViBE
#endif
@@ -0,0 +1,22 @@
#pragma once
#include "ovamsICommand.h"
class vrpn_Button_Remote;
namespace OpenViBE {
namespace SSVEPMindShooter {
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 SSVEPMindShooter
} // namespace OpenViBE
@@ -0,0 +1 @@
#pragma once
@@ -0,0 +1,153 @@
/*
* Notes:
*
* - This demo used to be called 'Impact Shooter' before being renamed to 'Mind Shooter'. The various
* mentions of 'Impact' are propagating from that time and should be cleaned up one day.
*
*
*/
#if defined(TARGET_HAS_ThirdPartyOgre3DTerrain)
#include "ovams_defines.h"
#include <openvibe/ov_all.h>
#include <toolkit/ovtk_all.h>
#include <openvibe/ov_directories.h>
#include "ovamsCApplication.h"
#include "GenericStimulator/ovamsCGenericStimulatorApplication.h"
#include "Impact/ovamsCImpactApplication.h"
int main(const int argc, char** argv)
{
if (argc != 3)
{
std::cout << "Usage : " << argv[0] << " <application-type> <scenario path>\n";
exit(1);
}
// initialize the OpenViBE kernel
OpenViBE::CKernelLoader kernelLoader;
OpenViBE::CString error;
OpenViBE::Kernel::IKernelDesc* kernelDesc = nullptr;
OpenViBE::Kernel::IKernelContext* kernelContext = nullptr;
OpenViBE::Kernel::ILogManager* logManager = nullptr;
const OpenViBE::CString applicationString = OpenViBE::CString(argv[1]);
const OpenViBE::CString scenarioFolder = OpenViBE::CString(argv[2]);
OpenViBE::CString applicationType, applicationSubtype;
if (applicationString == OpenViBE::CString("generic"))
{
applicationType = "generic";
applicationSubtype = "";
}
else if (applicationString == OpenViBE::CString("impact-trainer"))
{
applicationType = "impact";
applicationSubtype = "trainer";
}
else if (applicationString == OpenViBE::CString("impact-shooter"))
{
applicationType = "impact";
applicationSubtype = "shooter";
}
else
{
std::cout << "[ERROR] unknown command line parameter '" << applicationString << "'\n";
exit(3);
}
#ifdef TARGET_OS_Windows
std::cout << "[ INF ] Loading Windows kernel\n";
if (!kernelLoader.load(OpenViBE::Directories::getBinDir() + "/openvibe-kernel.dll", &error))
#else
std::cout << "[ INF ] Loading Linux kernel\n";
if(!kernelLoader.load(OpenViBE::Directories::getLibDir() + "/libopenvibe-kernel.so", &error))
#endif
{
std::cout << "[ FAILED ] Error loading kernel (" << error << ")" << "\n";
exit(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"; }
else
{
std::cout << "[ INF ] Got kernel descriptor, trying to create kernel\n";
kernelContext = kernelDesc->createKernel("ssvep-stimulator", OpenViBE::Directories::getDataDir() + "/kernel/openvibe.conf");
if (!kernelContext) { std::cout << "[ FAILED ] No kernel created by kernel descriptor\n"; }
else
{
kernelContext->initialize();
OpenViBE::Toolkit::initialize(*kernelContext);
OpenViBE::Kernel::IConfigurationManager* configManager = &(kernelContext->getConfigurationManager());
configManager->addConfigurationFromFile(configManager->expand("${Path_Data}/kernel/openvibe.conf"));
logManager = &(kernelContext->getLogManager());
// (*l_poLogManager) << Kernel::LogLevel_Info << configManager->expand("${UserHome}") << "\n";
const OpenViBE::CString configFile = scenarioFolder + "/appconf/application-configuration.conf";
if (!configManager->addConfigurationFromFile(configFile))
{
(*logManager) << OpenViBE::Kernel::LogLevel_Error << "Unable to read [" << configFile << "]\n";
exit(3);
}
// This folder contains resources such as textures etc
configManager->createConfigurationToken("SSVEP_MindShooterFolderName", "ssvep-mind-shooter");
// This folder is the runtime scenario path
configManager->createConfigurationToken("SSVEP_MindShooterScenarioPath", scenarioFolder);
}
}
OpenViBE::SSVEPMindShooter::CApplication* app;
if (applicationType == OpenViBE::CString("generic"))
{
(*logManager) << OpenViBE::Kernel::LogLevel_Debug << "+ app = new SSVEPMindShooter::CGenericStimulatorApplication(...)\n";
app = new OpenViBE::SSVEPMindShooter::CGenericStimulatorApplication(scenarioFolder);
}
else if (applicationType == OpenViBE::CString("impact"))
{
(*logManager) << OpenViBE::Kernel::LogLevel_Debug << "+ app = new SSVEPMindShooter::CImpactApplication(...)\n";
(*logManager) << OpenViBE::Kernel::LogLevel_Info << "application subtype " << applicationSubtype << "\n";
app = new OpenViBE::SSVEPMindShooter::CImpactApplication(scenarioFolder, applicationSubtype);
}
else
{
(*logManager) << OpenViBE::Kernel::LogLevel_Error << "Wrong application identifier specified\n";
exit(1);
}
if (!app->setup(kernelContext))
{
(*logManager) << OpenViBE::Kernel::LogLevel_Error << "Cannot proceed, exiting\n";
exit(2);
}
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 Mind Shooter has not been compiled as it depends on Ogre (missing/disabled)\n";
return -1;
}
#endif