begin refactor parallel connection

This commit is contained in:
Emil Axelsson
2016-09-08 18:04:06 +02:00
parent 67f1a389d2
commit 41fafcb5df
10 changed files with 416 additions and 1115 deletions

View File

@@ -47,107 +47,6 @@ class SceneGraphNode;
namespace interaction {
//#define USE_OLD_INTERACTIONHANDLER
#ifdef USE_OLD_INTERACTIONHANDLER
class InteractionHandler : public properties::PropertyOwner {
public:
InteractionHandler();
~InteractionHandler();
// Mutators
void setKeyboardController(KeyboardController* controller);
void setMouseController(MouseController* controller);
void setFocusNode(SceneGraphNode* node);
void setCamera(Camera* camera);
void setInteractionSensitivity(float sensitivity);
void resetKeyBindings();
void setInvertRoll(bool invert);
void setInvertRotation(bool invert);
void addController(Controller* controller);
void addKeyframe(const network::datamessagestructures::PositionKeyframe &kf);
void clearKeyframes();
void bindKey(Key key, KeyModifier modifier, std::string lua);
void lockControls();
void unlockControls();
void update(double deltaTime);
// Accessors
const SceneGraphNode* const focusNode() const;
const Camera* const camera() const;
double deltaTime() const;
float interactionSensitivity() const;
bool invertRoll() const;
bool invertRotation() const;
/**
* Returns the Lua library that contains all Lua functions available to affect the
* interaction. The functions contained are
* - openspace::luascriptfunctions::setOrigin
* \return The Lua library that contains all Lua functions available to affect the
* interaction
*/
static scripting::LuaLibrary luaLibrary();
// Callback functions
void keyboardCallback(Key key, KeyModifier modifier, KeyAction action);
void mouseButtonCallback(MouseButton button, MouseAction action);
void mousePositionCallback(double x, double y);
void mouseScrollWheelCallback(double pos);
// Interaction functions
void orbitDelta(const glm::quat& rotation);
void orbit(const float &dx, const float &dy, const float &dz, const float &dist);
void rotateDelta(const glm::quat& rotation);
void distanceDelta(const PowerScaledScalar& distance, size_t iterations = 0);
void lookAt(const glm::quat& rotation);
void setRotation(const glm::quat& rotation);
private:
// Remove copy and move constructors
InteractionHandler(const InteractionHandler&) = delete;
InteractionHandler& operator=(const InteractionHandler&) = delete;
InteractionHandler(InteractionHandler&&) = delete;
InteractionHandler& operator=(InteractionHandler&&) = delete;
// Settings
float _controllerSensitivity;
bool _invertRoll;
bool _invertRotation;
// Pointers to entities to affect
Camera* _camera;
SceneGraphNode* _focusNode;
// Cached data
double _deltaTime;
std::mutex _mutex;
//bool _validKeyLua;
std::multimap<KeyWithModifier, std::string > _keyLua;
KeyboardController* _keyboardController;
MouseController* _mouseController;
std::vector<Controller*> _controllers;
properties::StringProperty _origin;
properties::StringProperty _coordinateSystem;
//remote controller
std::vector<network::datamessagestructures::PositionKeyframe> _keyframes;
double _currentKeyframeTime;
std::mutex _keyframeMutex;
};
#else // USE_OLD_INTERACTIONHANDLER
class InteractionHandler : public properties::PropertyOwner
{
public:
@@ -165,7 +64,7 @@ public:
void resetKeyBindings();
void addKeyframe(const network::datamessagestructures::PositionKeyframe &kf);
void addKeyframe(const network::datamessagestructures::CameraKeyframe &kf);
void clearKeyframes();
void bindKey(Key key, KeyModifier modifier, std::string lua);
@@ -232,8 +131,6 @@ private:
properties::FloatProperty _rapidness;
};
#endif // USE_OLD_INTERACTIONHANDLER
} // namespace interaction
} // namespace openspace

View File

@@ -56,7 +56,7 @@ namespace interaction {
void mouseScrollWheelCallback(double mouseScrollDelta);
// Mutators
void addKeyframe(const network::datamessagestructures::PositionKeyframe &kf);
void addKeyframe(const network::datamessagestructures::CameraKeyframe &kf);
void clearKeyframes();
// Accessors
@@ -64,7 +64,7 @@ namespace interaction {
const std::list<MouseButton>& getPressedMouseButtons() const;
glm::dvec2 getMousePosition() const;
double getMouseScrollDelta() const;
std::vector<network::datamessagestructures::PositionKeyframe>& getKeyFrames() const;
std::vector<network::datamessagestructures::CameraKeyframe>& getKeyFrames() const;
bool isKeyPressed(std::pair<Key, KeyModifier> keyModPair) const;
bool isMouseButtonPressed(MouseButton mouseButton) const;
@@ -76,8 +76,7 @@ namespace interaction {
double _mouseScrollDelta;
// Remote input via keyframes
std::vector<network::datamessagestructures::PositionKeyframe> _keyframes;
std::mutex _keyframeMutex;
std::vector<network::datamessagestructures::CameraKeyframe> _keyframes;
};

View File

@@ -33,33 +33,38 @@
#include <glm/gtx/quaternion.hpp>
//openspace includes
#include <openspace/util/powerscaledcoordinate.h>
#include <openspace/util/camera.h>
namespace openspace{
namespace network{
namespace datamessagestructures{
enum type{
PositionData = 0,
namespace datamessagestructures {
enum class Type : uint32_t {
CameraData = 0,
TimeData,
ScriptData
};
struct PositionKeyframe{
glm::quat _viewRotationQuat;
psc _position;
double _timeStamp;
struct CameraKeyframe {
CameraKeyframe() {}
CameraKeyframe(const std::vector<char> &buffer) {
deserialize(buffer);
}
glm::dvec3 _position;
glm::dquat _rotation;
double _timestamp;
void serialize(std::vector<char> &buffer){
//add position
buffer.insert(buffer.end(), reinterpret_cast<char*>(&_position), reinterpret_cast<char*>(&_position) + sizeof(_position));
//add orientation
buffer.insert(buffer.end(), reinterpret_cast<char*>(&_viewRotationQuat), reinterpret_cast<char*>(&_viewRotationQuat) + sizeof(_viewRotationQuat));
buffer.insert(buffer.end(), reinterpret_cast<char*>(&_rotation), reinterpret_cast<char*>(&_rotation) + sizeof(_rotation));
//add timestamp
buffer.insert(buffer.end(), reinterpret_cast<char*>(&_timeStamp), reinterpret_cast<char*>(&_timeStamp) + sizeof(_timeStamp));
buffer.insert(buffer.end(), reinterpret_cast<char*>(&_timestamp), reinterpret_cast<char*>(&_timestamp) + sizeof(_timestamp));
};
void deserialize(const std::vector<char> &buffer){
@@ -72,17 +77,21 @@ namespace openspace{
offset += size;
//orientation
size = sizeof(_viewRotationQuat);
memcpy(&_viewRotationQuat, buffer.data() + offset, size);
size = sizeof(_rotation);
memcpy(&_rotation, buffer.data() + offset, size);
offset += size;
//timestamp
size = sizeof(_timeStamp);
memcpy(&_timeStamp, buffer.data() + offset, size);
size = sizeof(_timestamp);
memcpy(&_timestamp, buffer.data() + offset, size);
};
};
struct TimeKeyframe{
struct TimeKeyframe {
TimeKeyframe() {}
TimeKeyframe(const std::vector<char> &buffer) {
deserialize(buffer);
}
double _time;
double _dt;
@@ -128,31 +137,20 @@ namespace openspace{
};
};
struct ScriptMessage{
uint16_t _scriptlen;
struct ScriptMessage {
ScriptMessage() {}
ScriptMessage(const std::vector<char> &buffer) {
deserialize(buffer);
}
std::string _script;
void serialize(std::vector<char> &buffer){
//add script length
buffer.insert(buffer.end(), reinterpret_cast<char*>(&_scriptlen), reinterpret_cast<char*>(&_scriptlen) + sizeof(_scriptlen));
//add script
buffer.insert(buffer.end(), _script.begin(), _script.end());
};
void deserialize(const std::vector<char> &buffer){
int offset = 0;
int size = 0;
//size of script
size = sizeof(uint16_t);
memcpy(&_scriptlen, buffer.data() + offset, size);
offset += size;
//actual script
_script.assign(buffer.begin() + offset, buffer.end());
_script.assign(buffer.begin(), buffer.end());
};
};

View File

@@ -36,9 +36,9 @@
//std includes
#include <string>
#include <vector>
#include <deque>
#include <atomic>
#include <thread>
#include <sstream>
#include <mutex>
#include <map>
#include <condition_variable>
@@ -63,6 +63,35 @@ namespace openspace{
namespace network{
enum class MessageType : uint32_t {
Authentication = 0,
Data,
HostInformation,
HostshipRequest,
HostshipResignation
};
struct Message {
Message() {};
Message(MessageType t, const std::vector<char>& c)
: type(t)
, content(c)
{};
MessageType type;
std::vector<char> content;
};
struct DataMessage {
DataMessage() {};
DataMessage(network::datamessagestructures::Type t, const std::vector<char>& c)
: type(t)
, content(c)
{};
network::datamessagestructures::Type type;
std::vector<char> content;
};
class ParallelConnection{
public:
@@ -82,24 +111,19 @@ namespace openspace{
void requestHostship(const std::string &password);
void resignHostship();
void setPassword(const std::string &password);
void signalDisconnect();
void preSynchronization();
void sendScript(const std::string& script);
void scriptMessage(const std::string propIdentifier, const std::string propValue);
//void scriptMessage(const std::string propIdentifier, const std::string propValue);
enum MessageTypes{
Authentication=0,
Initialization,
Data,
Script, //obsolete now
HostInfo,
InitializationRequest,
HostshipRequest,
InitializationCompleted
};
/**
* Returns the Lua library that contains all Lua functions available to affect the
@@ -114,28 +138,15 @@ namespace openspace{
private:
//@TODO change this into the ghoul hasher for client AND server
uint32_t hash(const std::string &val){
uint32_t hashVal = 0, i;
size_t len = val.length();
for (hashVal = i = 0; i < len; ++i){
hashVal += val.c_str()[i];
hashVal += (hashVal << 10);
hashVal ^= (hashVal >> 6);
}
hashVal += (hashVal << 3);
hashVal ^= (hashVal >> 11);
hashVal += (hashVal << 15);
return hashVal;
};
void queueMessage(std::vector<char> message);
uint32_t hash(const std::string &val);
void queueOutMessage(const Message& message);
void queueOutDataMessage(const DataMessage& dataMessage);
void queueInMessage(const Message& message);
void disconnect();
void writeHeader(std::vector<char> &buffer, uint32_t messageType);
void closeSocket();
@@ -147,26 +158,18 @@ namespace openspace{
void listenCommunication();
void delegateDecoding(uint32_t type);
void handleMessage(const Message&);
void initializationMessageReceived();
void dataMessageReceived(const std::vector<char>& messageContent);
void dataMessageReceived();
void hostInfoMessageReceived();
void hostInfoMessageReceived(const std::vector<char>& messageContent);
void initializationRequestMessageReceived();
void broadcast();
int headerSize();
int receiveData(_SOCKET & socket, std::vector<char> &buffer, int length, int flags);
void sendFunc();
bool parseHints(addrinfo &info);
void threadManagement();
std::string scriptFromPropertyAndValue(const std::string property, const std::string value);
@@ -176,24 +179,27 @@ namespace openspace{
std::string _address;
std::string _name;
_SOCKET _clientSocket;
std::thread *_connectionThread;
std::thread *_broadcastThread;
std::thread *_sendThread;
std::thread *_listenThread;
std::thread *_handlerThread;
std::unique_ptr<std::thread> _connectionThread;
std::unique_ptr<std::thread> _broadcastThread;
std::unique_ptr<std::thread> _sendThread;
std::unique_ptr<std::thread> _listenThread;
std::unique_ptr<std::thread> _handlerThread;
std::atomic<bool> _isHost;
std::atomic<bool> _isConnected;
std::atomic<bool> _performDisconnect;
std::atomic<bool> _isRunning;
std::atomic<bool> _tryConnect;
std::atomic<bool> _disconnect;
std::atomic<bool> _initializationTimejumpRequired;
std::condition_variable _disconnectCondition;
std::mutex _disconnectMutex;
std::vector<std::vector<char>> _sendBuffer;
std::mutex _sendBufferMutex;
std::condition_variable _sendCondition;
std::deque<Message> _sendBuffer;
std::mutex _sendBufferMutex;
std::deque<Message> _receiveBuffer;
std::mutex _receiveBufferMutex;
network::datamessagestructures::TimeKeyframe _latestTimeKeyframe;
std::mutex _timeKeyframeMutex;

View File

@@ -56,574 +56,6 @@ namespace {
namespace openspace {
namespace interaction {
#ifdef USE_OLD_INTERACTIONHANDLER
InteractionHandler::InteractionHandler()
: properties::PropertyOwner()
, _camera(nullptr)
, _focusNode(nullptr)
, _deltaTime(0.0)
//, _validKeyLua(false)
, _controllerSensitivity(1.f)
, _invertRoll(true)
, _invertRotation(false)
, _keyboardController(nullptr)
, _mouseController(nullptr)
, _origin("origin", "Origin", "")
, _coordinateSystem("coordinateSystem", "Coordinate System", "")
, _currentKeyframeTime(-1.0)
{
setName("Interaction");
_origin.onChange([this](){
SceneGraphNode* node = sceneGraphNode(_origin.value());
if (!node) {
LWARNING("Could not find a node in scenegraph called '" << _origin.value() <<"'");
return;
}
setFocusNode(node);
});
addProperty(_origin);
_coordinateSystem.onChange([this](){
OsEng.renderEngine().changeViewPoint(_coordinateSystem.value());
});
addProperty(_coordinateSystem);
}
InteractionHandler::~InteractionHandler() {
delete _keyboardController;
delete _mouseController;
for (size_t i = 0; i < _controllers.size(); ++i)
delete _controllers[i];
}
void InteractionHandler::setKeyboardController(KeyboardController* controller) {
assert(controller);
delete _keyboardController;
_keyboardController = controller;
_keyboardController->setHandler(this);
}
void InteractionHandler::setMouseController(MouseController* controller) {
assert(controller);
delete _mouseController;
_mouseController = controller;
_mouseController->setHandler(this);
}
void InteractionHandler::addController(Controller* controller) {
assert(controller);
_controllers.push_back(controller);
controller->setHandler(this);
}
void InteractionHandler::lockControls() {
_mutex.lock();
}
void InteractionHandler::unlockControls() {
_mutex.unlock();
}
void InteractionHandler::update(double deltaTime) {
_deltaTime = deltaTime;
_mouseController->update(deltaTime);
bool hasKeys = false;
psc pos;
glm::quat q;
_keyframeMutex.lock();
if (_keyframes.size() > 4){ //wait until enough samples are buffered
hasKeys = true;
openspace::network::datamessagestructures::PositionKeyframe p0, p1, p2, p3;
p0 = _keyframes[0];
p1 = _keyframes[1];
p2 = _keyframes[2];
p3 = _keyframes[3];
//interval check
if (_currentKeyframeTime < p1._timeStamp){
_currentKeyframeTime = p1._timeStamp;
}
double t0 = p1._timeStamp;
double t1 = p2._timeStamp;
double fact = (_currentKeyframeTime - t0) / (t1 - t0);
//glm::dvec4 v = positionInterpCR.interpolate(fact, _keyframes[0]._position.dvec4(), _keyframes[1]._position.dvec4(), _keyframes[2]._position.dvec4(), _keyframes[3]._position.dvec4());
glm::dvec4 v = ghoul::interpolateLinear(fact, p1._position.dvec4(), p2._position.dvec4());
pos = psc(v.x, v.y, v.z, v.w);
q = ghoul::interpolateLinear(fact, p1._viewRotationQuat, p2._viewRotationQuat);
//we're done with this sample interval
if (_currentKeyframeTime >= p2._timeStamp){
_keyframes.erase(_keyframes.begin());
_currentKeyframeTime = p1._timeStamp;
}
_currentKeyframeTime += deltaTime;
}
_keyframeMutex.unlock();
if (hasKeys) {
_camera->setPosition(pos);
_camera->setRotation(q);
}
}
void InteractionHandler::setFocusNode(SceneGraphNode* node) {
if (_focusNode == node){
return;
}
_focusNode = node;
//orient the camera to the new node
psc focusPos = node->worldPosition();
psc camToFocus = focusPos - _camera->position();
glm::vec3 viewDir = glm::normalize(camToFocus.vec3());
glm::vec3 cameraView = glm::normalize(_camera->viewDirectionWorldSpace());
//set new focus position
_camera->setFocusPosition(node->worldPosition());
float dot = glm::dot(viewDir, cameraView);
//static const float Epsilon = 0.001f;
if (dot < 1.f && dot > -1.f) {
//if (glm::length(viewDir - cameraView) < 0.001) {
//if (viewDir != cameraView) {
glm::vec3 rotAxis = glm::normalize(glm::cross(viewDir, cameraView));
float angle = glm::angle(viewDir, cameraView);
glm::quat q = glm::angleAxis(angle, rotAxis);
//rotate view to target new focus
_camera->rotate(q);
}
}
const SceneGraphNode* const InteractionHandler::focusNode() const {
return _focusNode;
}
void InteractionHandler::setCamera(Camera* camera) {
assert(camera);
_camera = camera;
}
const Camera* const InteractionHandler::camera() const {
return _camera;
}
//void InteractionHandler::keyboardCallback(int key, int action) {
// if (_keyboardController) {
// auto start = ghoul::HighResClock::now();
// _keyboardController->keyPressed(KeyAction(action), Key(key), KeyModifier::None);
// auto end = ghoul::HighResClock::now();
// LINFO("Keyboard timing: " << std::chrono::duration_cast<std::chrono::nanoseconds>(end - start).count() << "ns");
// }
//}
void InteractionHandler::mouseButtonCallback(MouseButton button, MouseAction action) {
if (_mouseController)
_mouseController->button(button, action);
}
void InteractionHandler::mousePositionCallback(double x, double y) {
if (_mouseController)
// TODO Remap screen coordinates to [0,1]
_mouseController->move(static_cast<float>(x), static_cast<float>(y));
}
void InteractionHandler::mouseScrollWheelCallback(double pos) {
if (_mouseController)
_mouseController->scrollWheel(static_cast<int>(pos));
}
void InteractionHandler::orbit(const float &dx, const float &dy, const float &dz, const float &dist){
lockControls();
glm::vec3 cameraUp = glm::normalize((glm::inverse(_camera->viewRotationMatrix()) * glm::vec4(_camera->lookUpVectorCameraSpace(), 0))).xyz();
glm::vec3 cameraRight = glm::cross(glm::vec3(_camera->viewDirectionWorldSpace()), cameraUp);
glm::mat4 transform;
transform = glm::rotate(glm::radians(dx * 100.f), cameraUp) * transform;
transform = glm::rotate(glm::radians(dy * 100.f), cameraRight) * transform;
transform = glm::rotate(glm::radians(dz * 100.f), glm::vec3(_camera->viewDirectionWorldSpace())) * transform;
//get "old" focus position
psc camPos = _camera->position();
psc focusPos = _camera->focusPosition();
float distToFocusNodeCenter = (focusPos - camPos).length().lengthf();
float focusNodeBounds = _focusNode ? _focusNode->boundingSphere().lengthf() : 0.f;
float speedFactor = distToFocusNodeCenter - 0.098*focusNodeBounds;
float rotationSpeed = glm::min(0.00001f * speedFactor, 100.0f);
float zoomSpeed = glm::min(0.0000001f * speedFactor, 1.0f);
float rollSpeed = 100.0f;
glm::mat4 transform;
transform = glm::rotate(glm::radians(dx * rotationSpeed), cameraUp) * transform;
transform = glm::rotate(glm::radians(dy * rotationSpeed), cameraRight) * transform;
transform = glm::rotate(glm::radians(dz * rollSpeed), _camera->viewDirection()) * transform;
//// get camera position
//psc relative = _camera->position();
// get camera position (UNSYNCHRONIZED)
psc relative = _camera->unsynchedPosition();
//get relative vector
psc relative_focus_coordinate = relative - focusPos;
//rotate relative vector
relative_focus_coordinate = glm::inverse(transform) * relative_focus_coordinate.vec4();
//get new new position of focus node
psc origin;
if (_focusNode) {
origin = _focusNode->worldPosition();
}
//new camera position
relative = origin + relative_focus_coordinate;
psc target = relative + relative_focus_coordinate * dist * zoomSpeed;
//don't fly into objects
if ((target - origin).length() < focusNodeBounds){
//target = relative;
}
unlockControls();
_camera->setFocusPosition(origin);
_camera->setPosition(target);
_camera->rotate(glm::quat_cast(transform));
}
//void InteractionHandler::distance(const float &d){
//
// lockControls();
//
// psc relative = _camera->position();
// const psc origin = (_focusNode) ? _focusNode->worldPosition() : psc();
// psc relative_origin_coordinate = relative - origin;
// // addition 100% of bounds (fix later to something node specific?)
// float bounds = 2.f * (_focusNode ? _focusNode->boundingSphere().lengthf() : 0.f);
//
// psc target = relative + relative_origin_coordinate * d;// *fmaxf(bounds, (1.f - d));
// //don't fly into objects
// if ((target - origin).length() < bounds){
// target = relative;
// }
// _camera->setPosition(target);
//
// unlockControls();
//}
void InteractionHandler::orbitDelta(const glm::quat& rotation)
{
lockControls();
// the camera position
psc relative = _camera->position();
// should be changed to something more dynamic =)
psc origin;
if (_focusNode) {
origin = _focusNode->worldPosition();
}
psc relative_origin_coordinate = relative - origin;
//glm::mat4 rotation_matrix = glm::mat4_cast(glm::inverse(rotation));
//relative_origin_coordinate = relative_origin_coordinate.vec4() * glm::inverse(rotation);
relative_origin_coordinate = glm::inverse(rotation) * relative_origin_coordinate.vec4();
relative = relative_origin_coordinate + origin;
glm::mat4 la = glm::lookAt(_camera->position().vec3(), origin.vec3(), glm::rotate(rotation, glm::vec3(_camera->lookUpVectorCameraSpace())));
unlockControls();
_camera->setPosition(relative);
//camera_->rotate(rotation);
//camera_->setRotation(glm::mat4_cast(rotation));
_camera->setRotation(glm::quat_cast(la));
//camera_->setLookUpVector();
}
//<<<<<<< HEAD
//void InteractionHandler::distance(const PowerScaledScalar &dist, size_t iterations) {
// if (iterations > 5)
// return;
// //assert(this_);
// lockControls();
//
// psc relative = _camera->position();
// const psc origin = (_node) ? _node->worldPosition() : psc();
//
// psc relative_origin_coordinate = relative - origin;
// const glm::vec3 dir(relative_origin_coordinate.direction());
// glm::vec3 newdir = dir * dist[0];
//=======
void InteractionHandler::rotateDelta(const glm::quat& rotation)
{
_camera->rotate(rotation);
}
void InteractionHandler::distanceDelta(const PowerScaledScalar& distance, size_t iterations)
{
if (iterations > 5)
return;
//assert(this_);
lockControls();
psc relative = _camera->position();
const psc origin = (_focusNode) ? _focusNode->worldPosition() : psc();
unlockControls();
psc relative_origin_coordinate = relative - origin;
const glm::vec3 dir(relative_origin_coordinate.direction());
glm::vec3 newdir = dir * distance[0];
relative_origin_coordinate = newdir;
relative_origin_coordinate[3] = distance[1];
relative = relative + relative_origin_coordinate;
relative_origin_coordinate = relative - origin;
if (relative_origin_coordinate.vec4().x == 0.f && relative_origin_coordinate.vec4().y == 0.f && relative_origin_coordinate.vec4().z == 0.f)
// TODO: this shouldn't be allowed to happen; a mechanism to prevent the camera to coincide with the origin is necessary (ab)
return;
newdir = relative_origin_coordinate.direction();
// update only if on the same side of the origin
if (glm::angle(newdir, dir) < 90.0f) {
_camera->setPosition(relative);
}
else {
PowerScaledScalar d2 = distance;
d2[0] *= 0.75f;
d2[1] *= 0.85f;
distanceDelta(d2, iterations + 1);
}
}
void InteractionHandler::lookAt(const glm::quat& rotation)
{
}
void InteractionHandler::keyboardCallback(Key key, KeyModifier modifier, KeyAction action) {
// TODO package in script
const float speed = _controllerSensitivity;
const float dt = static_cast<float>(_deltaTime);
if (action == KeyAction::Press || action == KeyAction::Repeat) {
if ((key == Key::Right) && (modifier == KeyModifier::NoModifier)) {
glm::vec3 euler(0.0, speed * dt*0.4, 0.0);
glm::quat rot = glm::quat(euler);
rotateDelta(rot);
}
if ((key == Key::Left) && (modifier == KeyModifier::NoModifier)) {
glm::vec3 euler(0.0, -speed * dt*0.4, 0.0);
glm::quat rot = glm::quat(euler);
rotateDelta(rot);
}
if ((key == Key::Down) && (modifier == KeyModifier::NoModifier)) {
glm::vec3 euler(speed * dt*0.4, 0.0, 0.0);
glm::quat rot = glm::quat(euler);
rotateDelta(rot);
}
if ((key == Key::Up) && (modifier == KeyModifier::NoModifier)) {
glm::vec3 euler(-speed * dt*0.4, 0.0, 0.0);
glm::quat rot = glm::quat(euler);
rotateDelta(rot);
}
if ((key == Key::KeypadSubtract) && (modifier == KeyModifier::NoModifier)) {
glm::vec2 s = OsEng.renderEngine().camera()->scaling();
s[1] -= 0.5f;
OsEng.renderEngine().camera()->setScaling(s);
}
if ((key == Key::KeypadAdd) && (modifier == KeyModifier::NoModifier)) {
glm::vec2 s = OsEng.renderEngine().camera()->scaling();
s[1] += 0.5f;
OsEng.renderEngine().camera()->setScaling(s);
}
// iterate over key bindings
//_validKeyLua = true;
auto ret = _keyLua.equal_range({ key, modifier });
for (auto it = ret.first; it != ret.second; ++it) {
//OsEng.scriptEngine()->runScript(it->second);
OsEng.scriptEngine().queueScript(it->second);
//if (!_validKeyLua) {
// break;
//}
}
}
}
void InteractionHandler::resetKeyBindings() {
_keyLua.clear();
//_validKeyLua = false;
}
void InteractionHandler::bindKey(Key key, KeyModifier modifier, std::string lua) {
_keyLua.insert({
{key, modifier},
lua
});
}
scripting::LuaLibrary InteractionHandler::luaLibrary() {
return {
"",
{
{
"clearKeys",
&luascriptfunctions::clearKeys,
"",
"Clear all key bindings"
},
{
"bindKey",
&luascriptfunctions::bindKey,
"string, string",
"Binds a key by name to a lua string command"
},
{
"dt",
&luascriptfunctions::dt,
"",
"Get current frame time"
},
{
"distance",
&luascriptfunctions::distance,
"number",
"Change distance to origin",
true
},
{
"setInteractionSensitivity",
&luascriptfunctions::setInteractionSensitivity,
"number",
"Sets the global interaction sensitivity"
},
{
"interactionSensitivity",
&luascriptfunctions::interactionSensitivity,
"",
"Gets the current global interaction sensitivity"
},
{
"setInvertRoll",
&luascriptfunctions::setInvertRoll,
"bool",
"Sets the setting if roll movements are inverted"
},
{
"invertRoll",
&luascriptfunctions::invertRoll,
"",
"Returns the status of roll movement inversion"
},
{
"setInvertRotation",
&luascriptfunctions::setInvertRotation,
"bool",
"Sets the setting if rotation movements are inverted"
},
{
"invertRotation",
&luascriptfunctions::invertRotation,
"",
"Returns the status of rotation movement inversion"
}
}
};
}
void InteractionHandler::setRotation(const glm::quat& rotation)
{
_camera->setRotation(rotation);
}
double InteractionHandler::deltaTime() const {
return _deltaTime;
}
void InteractionHandler::setInteractionSensitivity(float sensitivity) {
_controllerSensitivity = sensitivity;
}
float InteractionHandler::interactionSensitivity() const {
return _controllerSensitivity;
}
void InteractionHandler::setInvertRoll(bool invert) {
_invertRoll = invert;
}
bool InteractionHandler::invertRoll() const {
return _invertRoll;
}
void InteractionHandler::setInvertRotation(bool invert) {
_invertRotation = invert;
}
bool InteractionHandler::invertRotation() const {
return _invertRotation;
}
void InteractionHandler::addKeyframe(const network::datamessagestructures::PositionKeyframe &kf){
_keyframeMutex.lock();
//save a maximum of 10 samples (1 seconds of buffer)
if (_keyframes.size() >= 10){
_keyframes.erase(_keyframes.begin());
}
_keyframes.push_back(kf);
_keyframeMutex.unlock();
}
void InteractionHandler::clearKeyframes(){
_keyframeMutex.lock();
_keyframes.clear();
_keyframeMutex.unlock();
}
#else // USE_OLD_INTERACTIONHANDLER
// InteractionHandler
InteractionHandler::InteractionHandler()
: _origin("origin", "Origin", "")
@@ -664,6 +96,11 @@ InteractionHandler::InteractionHandler()
"GlobeBrowsing",
std::make_shared<GlobeBrowsingInteractionMode>(_mouseStates)
));
_interactionModes.insert(
std::pair<std::string, std::shared_ptr<InteractionMode>>(
"Keyframe",
std::make_shared<KeyframeInteractionMode>()
));
// Set the interactionMode
_currentInteractionMode = _interactionModes["Orbital"];
@@ -1010,7 +447,7 @@ scripting::LuaLibrary InteractionHandler::luaLibrary() {
};
}
void InteractionHandler::addKeyframe(const network::datamessagestructures::PositionKeyframe &kf) {
void InteractionHandler::addKeyframe(const network::datamessagestructures::CameraKeyframe &kf) {
_inputState->addKeyframe(kf);
}
@@ -1019,20 +456,16 @@ void InteractionHandler::clearKeyframes() {
}
void InteractionHandler::serialize(SyncBuffer* syncBuffer) {
for each (auto var in _interactionModes)
{
for (auto var : _interactionModes) {
var.second->serialize(syncBuffer);
}
}
void InteractionHandler::deserialize(SyncBuffer* syncBuffer) {
for each (auto var in _interactionModes)
{
for (auto var : _interactionModes) {
var.second->deserialize(syncBuffer);
}
}
#endif // USE_OLD_INTERACTIONHANDLER
} // namespace interaction
} // namespace openspace

View File

@@ -57,22 +57,18 @@ namespace interaction {
}
void InputState::addKeyframe(const network::datamessagestructures::PositionKeyframe &kf) {
_keyframeMutex.lock();
void InputState::addKeyframe(const network::datamessagestructures::CameraKeyframe &kf) {
//save a maximum of 10 samples (1 seconds of buffer)
if (_keyframes.size() >= 10) {
_keyframes.erase(_keyframes.begin());
}
_keyframes.push_back(kf);
_keyframeMutex.unlock();
}
void InputState::clearKeyframes() {
_keyframeMutex.lock();
_keyframes.clear();
_keyframeMutex.unlock();
}
void InputState::keyboardCallback(Key key, KeyModifier modifier, KeyAction action) {

View File

@@ -64,6 +64,7 @@
#include "parallelconnection_lua.inl"
namespace {
const uint32_t ProtocolVersion = 2;
const std::string _loggerCat = "ParallelConnection";
}
@@ -86,12 +87,12 @@ ParallelConnection::ParallelConnection()
, _isHost(false)
, _isConnected(false)
, _tryConnect(false)
, _performDisconnect(false)
, _disconnect(false)
, _latestTimeKeyframeValid(false)
, _initializationTimejumpRequired(false)
{
//create handler thread
_handlerThread = new (std::nothrow) std::thread(&ParallelConnection::threadManagement, this);
_handlerThread = std::make_unique<std::thread>(&ParallelConnection::threadManagement, this);
}
ParallelConnection::~ParallelConnection(){
@@ -104,9 +105,6 @@ ParallelConnection::~ParallelConnection(){
//join handler
_handlerThread->join();
//and delete handler
delete _handlerThread;
}
void ParallelConnection::threadManagement(){
@@ -114,13 +112,13 @@ void ParallelConnection::threadManagement(){
// How about moving this out of the thread and into the destructor? ---abock
//while we're still running
while(_isRunning.load()){
while(_isRunning){
{
//lock disconnect mutex mutex
//not really needed since no data is modified but conditions need a mutex
std::unique_lock<std::mutex> unqlock(_disconnectMutex);
std::unique_lock<std::mutex> disconnectLock(_disconnectMutex);
//wait for a signal to disconnect
_disconnectCondition.wait(unqlock);
_disconnectCondition.wait(disconnectLock, [this]() { return _disconnect.load(); });
//perform actual disconnect
disconnect();
@@ -131,7 +129,9 @@ void ParallelConnection::threadManagement(){
void ParallelConnection::signalDisconnect(){
//signal handler thread to disconnect
_disconnectCondition.notify_all();
_disconnect = true;
_sendCondition.notify_all(); // Allow send function to terminate.
_disconnectCondition.notify_all(); // Unblock thread management thread.
}
void ParallelConnection::closeSocket(){
@@ -175,40 +175,33 @@ void ParallelConnection::disconnect(){
//tell broadcast thread to stop broadcasting (we're no longer host)
_isHost.store(false);
//signal send thread to stop waiting and finish current run
_sendCondition.notify_all();
//join connection thread and delete it
if(_connectionThread != nullptr){
_connectionThread->join();
delete _connectionThread;
_connectionThread = nullptr;
}
//join send thread and delete it
if (_sendThread != nullptr){
_sendThread->join();
delete _sendThread;
_sendThread = nullptr;
}
//join listen thread and delete it
if( _listenThread != nullptr){
_listenThread->join();
delete _listenThread;
_listenThread = nullptr;
}
//join broadcast thread and delete it
if(_broadcastThread != nullptr){
_broadcastThread->join();
delete _broadcastThread;
_broadcastThread = nullptr;
}
// disconnect and cleanup completed
_performDisconnect.store(false);
_disconnect = false;
}
}
@@ -225,11 +218,9 @@ void ParallelConnection::clientConnect(){
}
struct addrinfo *addresult = NULL, *ptr = NULL, hints;
#ifdef __WIN32__ //WinSock
ZeroMemory(&hints, sizeof(hints));
#else
memset(&hints, 0, sizeof(hints));
#endif
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
@@ -250,7 +241,7 @@ void ParallelConnection::clientConnect(){
_tryConnect.store(true);
//start connection thread
_connectionThread = new (std::nothrow) std::thread(&ParallelConnection::establishConnection, this, addresult);
_connectionThread = std::make_unique<std::thread>(&ParallelConnection::establishConnection, this, addresult);
}
@@ -266,14 +257,15 @@ void ParallelConnection::establishConnection(addrinfo *info){
signalDisconnect();
}
int flag = 1;
int trueFlag = 1;
int falseFlag = 0;
int result;
//set no delay
result = setsockopt(_clientSocket, /* socket affected */
IPPROTO_TCP, /* set option at TCP level */
TCP_NODELAY, /* name of option */
(char *)&flag, /* the cast is historical cruft */
(char *)&trueFlag, /* the cast is historical cruft */
sizeof(int)); /* length of option value */
//set send timeout
@@ -293,11 +285,11 @@ void ParallelConnection::establishConnection(addrinfo *info){
(char *)&timeout,
sizeof(timeout));
result = setsockopt(_clientSocket, SOL_SOCKET, SO_REUSEADDR, (char*)&flag, sizeof(int));
result = setsockopt(_clientSocket, SOL_SOCKET, SO_REUSEADDR, (char*)&falseFlag, sizeof(int));
if (result == SOCKET_ERROR)
LERROR("Failed to set socket option 'reuse address'. Error code: " << _ERRNO);
result = setsockopt(_clientSocket, SOL_SOCKET, SO_KEEPALIVE, (char*)&flag, sizeof(int));
result = setsockopt(_clientSocket, SOL_SOCKET, SO_KEEPALIVE, (char*)&trueFlag, sizeof(int));
if (result == SOCKET_ERROR)
LERROR("Failed to set socket option 'keep alive'. Error code: " << _ERRNO);
@@ -320,10 +312,10 @@ void ParallelConnection::establishConnection(addrinfo *info){
_isConnected.store(true);
//start sending messages
_sendThread = new (std::nothrow) std::thread(&ParallelConnection::sendFunc, this);
_sendThread = std::make_unique<std::thread>(&ParallelConnection::sendFunc, this);
//start listening for communication
_listenThread = new (std::nothrow) std::thread(&ParallelConnection::listenCommunication, this);
_listenThread = std::make_unique<std::thread>(&ParallelConnection::listenCommunication, this);
//we no longer need to try to establish connection
_tryConnect.store(false);
@@ -332,7 +324,7 @@ void ParallelConnection::establishConnection(addrinfo *info){
sendAuthentication();
}
#ifdef __WIN32__
#ifdef WIN32
//on windows: try to connect once per second
std::this_thread::sleep_for(std::chrono::seconds(1));
#else
@@ -353,52 +345,43 @@ void ParallelConnection::establishConnection(addrinfo *info){
freeaddrinfo(info);
}
void ParallelConnection::sendAuthentication(){
void ParallelConnection::sendAuthentication() {
//length of this nodes name
uint16_t namelen = static_cast<uint16_t>(_name.length());
uint32_t nameLength = static_cast<uint32_t>(_name.length());
//total size of the buffer, header + size of passcodde + namelength + size of namelength
int size = headerSize() + sizeof(uint32_t) + sizeof(namelen) + static_cast<int>(namelen);
//total size of the buffer: (passcode + namelength + name)
size_t size = 2 * sizeof(uint32_t) + nameLength;
//create and reserve buffer
std::vector<char> buffer;
buffer.reserve(size);
//write header to buffer
writeHeader(buffer, MessageTypes::Authentication);
//write passcode to buffer
buffer.insert(buffer.end(), reinterpret_cast<char*>(&_passCode), reinterpret_cast<char*>(&_passCode) + sizeof(uint32_t));
//write the length of the nodes name to buffer
buffer.insert(buffer.end(), reinterpret_cast<char*>(&namelen), reinterpret_cast<char*>(&namelen) + sizeof(uint16_t));
buffer.insert(buffer.end(), reinterpret_cast<char*>(&nameLength), reinterpret_cast<char*>(&nameLength) + sizeof(uint32_t));
//write this nodes name to buffer
//write this node's name to buffer
buffer.insert(buffer.end(), _name.begin(), _name.end());
//send buffer
queueMessage(buffer);
queueOutMessage(Message(MessageType::Authentication, buffer));
}
void ParallelConnection::delegateDecoding(uint32_t type){
switch (type){
case MessageTypes::Authentication:
//not used
void ParallelConnection::queueInMessage(const Message& message) {
std::unique_lock<std::mutex> unqlock(_receiveBufferMutex);
_receiveBuffer.push_back(message);
}
void ParallelConnection::handleMessage(const Message& message) {
switch (message.type){
case MessageType::Data:
dataMessageReceived(message.content);
break;
case MessageTypes::Initialization:
initializationMessageReceived();
break;
case MessageTypes::Data:
dataMessageReceived();
break;
case MessageTypes::Script:
//not used
break;
case MessageTypes::HostInfo:
hostInfoMessageReceived();
break;
case MessageTypes::InitializationRequest:
initializationRequestMessageReceived();
case MessageType::HostInformation:
hostInfoMessageReceived(message.content);
break;
default:
//unknown message type
@@ -406,6 +389,7 @@ void ParallelConnection::delegateDecoding(uint32_t type){
}
}
/*
void ParallelConnection::initializationMessageReceived(){
int result;
@@ -476,72 +460,29 @@ void ParallelConnection::initializationMessageReceived(){
writeHeader(buffer, MessageTypes::InitializationCompleted);
//let the server know
queueMessage(buffer);
std::cout << "initialization message recieved queue" << std::endl;
queueMessage(InitializationCompleted, buffer);
//we also need to force a time jump just to ensure that the server and client are synced
_initializationTimejumpRequired.store(true);
}
*/
void ParallelConnection::dataMessageReceived(){
int result;
uint16_t msglen;
uint16_t type;
//create a buffer to hold the size of streamdata message
std::vector<char> buffer;
buffer.resize(sizeof(type));
//read type of data message
result = receiveData(_clientSocket, buffer, sizeof(type), 0);
if (result <= 0){
//error
LERROR("Failed to read type of data message received.");
return;
}
void ParallelConnection::dataMessageReceived(const std::vector<char>& messageContent) {
//the type of data message received
type =(*(reinterpret_cast<uint16_t*>(buffer.data())));
//read size of streamdata message
result = receiveData(_clientSocket, buffer, sizeof(msglen), 0);
if (result <= 0){
//error
LERROR("Failed to read size of data message received.");
return;
}
//the size in bytes of the streamdata message
msglen = (*(reinterpret_cast<uint16_t*>(buffer.data())));
//resize the buffer to be able to read the streamdata
buffer.clear();
buffer.resize(msglen);
//read the data into buffer
result = receiveData(_clientSocket, buffer, msglen, 0);
if (result <= 0){
//error
LERROR("Failed to read data message.");
return;
}
//which type of data message was received?
uint32_t type = *(reinterpret_cast<const uint32_t*>(messageContent.data()));
std::vector<char> buffer(messageContent.begin() + sizeof(uint32_t), messageContent.end());
switch(type){
case network::datamessagestructures::PositionData:{
//position data message
//create and read a position keyframe from the data buffer
network::datamessagestructures::PositionKeyframe kf;
kf.deserialize(buffer);
//add the keyframe to the interaction handler
case network::datamessagestructures::Type::CameraData: {
network::datamessagestructures::CameraKeyframe kf(buffer);
OsEng.interactionHandler().addKeyframe(kf);
break;
}
case network::datamessagestructures::TimeData:{
case network::datamessagestructures::Type::TimeData: {
/*
//time data message
//create and read a time keyframe from the data buffer
network::datamessagestructures::TimeKeyframe tf;
@@ -575,17 +516,14 @@ void ParallelConnection::dataMessageReceived(){
//the keyframe is now valid for use
_latestTimeKeyframeValid.store(true);
*/
break;
}
case network::datamessagestructures::ScriptData:{
//script data message
//create and read a script message from data buffer
case network::datamessagestructures::Type::ScriptData: {
network::datamessagestructures::ScriptMessage sm;
sm.deserialize(buffer);
//Que script to be executed by script engine
OsEng.scriptEngine().queueScript(sm._script);
break;
}
default:{
@@ -595,113 +533,128 @@ void ParallelConnection::dataMessageReceived(){
}
}
void ParallelConnection::queueMessage(std::vector<char> message){
{
std::unique_lock<std::mutex> unqlock(_sendBufferMutex);
_sendBuffer.push_back(message);
_sendCondition.notify_all();
}
void ParallelConnection::queueOutDataMessage(const DataMessage& dataMessage) {
uint32_t dataMessageTypeOut = static_cast<uint32_t>(dataMessage.type);
std::vector<char> messageContent;
messageContent.insert(messageContent.end(),
reinterpret_cast<const char*>(&dataMessageTypeOut),
reinterpret_cast<const char*>(&dataMessageTypeOut) + sizeof(uint32_t));
messageContent.insert(messageContent.end(),
dataMessage.content.begin(),
dataMessage.content.end());
queueOutMessage(Message(MessageType::Data, messageContent));
}
void ParallelConnection::queueOutMessage(const Message& message) {
std::unique_lock<std::mutex> unqlock(_sendBufferMutex);
_sendBuffer.push_back(message);
_sendCondition.notify_all();
}
void ParallelConnection::sendFunc(){
int result;
//while we're connected
while(_isConnected.load()){
{
//wait for signal then lock mutex and send first queued message
std::unique_lock<std::mutex> unqlock(_sendBufferMutex);
_sendCondition.wait_for(unqlock, std::chrono::milliseconds(500));
if(!_sendBuffer.empty()){
while(!_sendBuffer.empty()){
result = send(_clientSocket, _sendBuffer.front().data(), _sendBuffer.front().size(), 0);
_sendBuffer.erase(_sendBuffer.begin());
//make sure everything went well
if (result == SOCKET_ERROR){
//failed to send message
LERROR("Failed to send message.\nError: " << _ERRNO << " detected in connection, disconnecting.");
//signal that a disconnect should be performed
signalDisconnect();
}
}
while(_isConnected && !_disconnect) {
//wait for signal then lock mutex and send first queued message
std::unique_lock<std::mutex> unqlock(_sendBufferMutex);
_sendCondition.wait(unqlock);
while (!_sendBuffer.empty()) {
const Message& message = _sendBuffer.front();
std::vector<char> header;
//insert header into buffer
header.push_back('O');
header.push_back('S');
uint32_t messageTypeOut = static_cast<uint32_t>(message.type);
uint32_t messageSizeOut = static_cast<uint32_t>(message.content.size());
header.insert(header.end(),
reinterpret_cast<const char*>(&ProtocolVersion),
reinterpret_cast<const char*>(&ProtocolVersion) + sizeof(uint32_t));
header.insert(header.end(),
reinterpret_cast<const char*>(&messageTypeOut),
reinterpret_cast<const char*>(&messageTypeOut) + sizeof(uint32_t));
header.insert(header.end(),
reinterpret_cast<const char*>(&messageSizeOut),
reinterpret_cast<const char*>(&messageSizeOut) + sizeof(uint32_t));
result = send(_clientSocket, header.data(), header.size(), 0);
result = send(_clientSocket, message.content.data(), message.content.size(), 0);
if (result == SOCKET_ERROR) {
LERROR("Failed to send message.\nError: " << _ERRNO << " detected in connection, disconnecting.");
signalDisconnect();
}
_sendBuffer.erase(_sendBuffer.begin());
}
}
}
}
void ParallelConnection::hostInfoMessageReceived(){
//create buffer
std::vector<char> hostflag;
//resize to hold a flag saying if we're host or not
hostflag.resize(1);
//read data into buffer
int result = receiveData(_clientSocket, hostflag, 1, 0);
//enough data was read
if (result > 0){
//we've been assigned as host
if (hostflag.at(0) == 1){
void ParallelConnection::hostInfoMessageReceived(const std::vector<char>& message){
if (message.size() < 1) {
LERROR("Malformed host info message.");
return;
}
char hostInfo = message[0];
if (hostInfo == 1) { // assigned as host
if (_isHost.load()) {
//we're already host, do nothing (dummy check)
if (_isHost.load()){
return;
}
else{
//we're the host
_isHost.store(true);
//start broadcasting
_broadcastThread = new (std::nothrow) std::thread(&ParallelConnection::broadcast, this);
}
return;
}
else{ //we've been assigned as client
//we were broadcasting but should stop now
if (_isHost.load()){
_isHost.store(true);
//stop broadcast loop
_isHost.store(false);
//and delete broadcasting thread
if (_broadcastThread != nullptr){
_broadcastThread->join();
delete _broadcastThread;
_broadcastThread = nullptr;
}
}
else{
//we were not broadcasting so nothing to do
}
//clear buffered any keyframes
OsEng.interactionHandler().clearKeyframes();
//request init package from the host
int size = headerSize();
std::vector<char> buffer;
buffer.reserve(size);
//write header
writeHeader(buffer, MessageTypes::InitializationRequest);
//start broadcasting
_broadcastThread = std::make_unique<std::thread>(&ParallelConnection::broadcast, this);
//send message
queueMessage(buffer);
} else { // assigned as client
if (!_isHost.load()) {
//we're already a client, do nothing (dummy check)
return;
}
//stop broadcast loop
_isHost.store(false);
// delete broadcasting thread
if (_broadcastThread != nullptr) {
_broadcastThread->join();
_broadcastThread = nullptr;
}
OsEng.interactionHandler().clearKeyframes();
//clear buffered any keyframes
//request init package from the host
//int size = headerSize();
//std::vector<char> buffer;
//buffer.reserve(size);
//write header
//writeHeader(buffer, MessageTypes::InitializationRequest);
//send message
//std::cout << "host info queue" << std::endl;
//queueMessage(MessageTypes::InitializationRequest, buffer);
}
else{
LERROR("Error " << _ERRNO << " detected in connection, disconnecting.");
signalDisconnect();
}
}
void ParallelConnection::initializationRequestMessageReceived(){
//void ParallelConnection::initializationRequestMessageReceived(const std::vector<char>& message){
/*
//get current state as scripts
std::vector<std::string> scripts;
std::map<std::string, std::string>::iterator state_it;
@@ -767,56 +720,66 @@ void ParallelConnection::initializationRequestMessageReceived(){
buffer.insert(buffer.end(), scriptbuffer.begin(), scriptbuffer.end());
//queue message
queueMessage(buffer);
}
std::cout << "initializationRequest queue" << std::endl;
queueMessage(MessageType::Initialization, buffer);
*/
//}
void ParallelConnection::listenCommunication(){
void ParallelConnection::listenCommunication() {
constexpr size_t headerSize = 2 * sizeof(char) + 3 * sizeof(uint32_t);
//create basic buffer for receiving first part of messages
std::vector<char> buffer;
//size of the header
buffer.resize(headerSize());
int result;
std::vector<char> headerBuffer(headerSize);
std::vector<char> messageBuffer;
int nBytesRead = 0;
//while we're still connected
while (_isConnected.load()){
//receive the first parts of a message
result = receiveData(_clientSocket, buffer, headerSize(), 0);
while (_isConnected.load()) {
//receive the header data
nBytesRead = receiveData(_clientSocket, headerBuffer, headerSize, 0);
//if enough data was received
if (result > 0){
//make sure that header matches this version of OpenSpace
if (buffer[0] == 'O' && //Open
buffer[1] == 'S' && //Space
buffer[2] == OPENSPACE_VERSION_MAJOR && // major version
buffer[3] == OPENSPACE_VERSION_MINOR // minor version
)
{
//parse type
uint32_t type = (*(reinterpret_cast<uint32_t*>(&buffer[4])));
//and delegate decoding depending on type
delegateDecoding(type);
}
else{
LERROR("Error: Client OpenSpace version " << OPENSPACE_VERSION_MAJOR << ", " << OPENSPACE_VERSION_MINOR << " does not match server version " << buffer[2] <<", " << buffer[3] << std::endl << "Message not decoded.");
}
}
else{
if (result == 0){
//connection rejected
LERROR("Parallel connection rejected, disconnecting...");
}
else{
LERROR("Error " << _ERRNO << " detected in connection, disconnecting!");
}
//signal that a disconnect should be performed
if (nBytesRead <= 0) {
LERROR("Error " << _ERRNO << " detected in connection when reading header, disconnecting!");
signalDisconnect();
break;
}
//make sure that header matches this version of OpenSpace
if (!(headerBuffer[0] == 'O' && headerBuffer[1] && 'S')) {
LERROR("Expected to read message header 'OS' from socket.");
signalDisconnect();
break;
}
uint32_t *ptr = reinterpret_cast<uint32_t*>(&headerBuffer[2]);
uint32_t protocolVersionIn = *(ptr++);
uint32_t messageTypeIn = *(ptr++);
uint32_t messageSizeIn = *(ptr++);
if (protocolVersionIn != ProtocolVersion) {
LERROR("Protocol versions do not match. Server version: " << protocolVersionIn << ", Client version: " << ProtocolVersion);
signalDisconnect();
break;
}
size_t messageSize = messageSizeIn;
// receive the payload
messageBuffer.resize(messageSize);
nBytesRead = receiveData(_clientSocket, messageBuffer, messageSize, 0);
if (nBytesRead <= 0) {
LERROR("Error " << _ERRNO << " detected in connection when reading message, disconnecting!");
signalDisconnect();
break;
}
//and delegate decoding depending on type
queueInMessage(Message(static_cast<MessageType>(messageTypeIn), messageBuffer));
}
}
@@ -859,18 +822,14 @@ bool ParallelConnection::isHost(){
void ParallelConnection::requestHostship(const std::string &password){
std::vector<char> buffer;
buffer.reserve(headerSize());
uint32_t passcode = hash(password);
//write header
writeHeader(buffer, MessageTypes::HostshipRequest);
//write passcode
buffer.insert(buffer.end(), reinterpret_cast<char*>(&passcode), reinterpret_cast<char*>(&passcode) + sizeof(uint32_t));
//send message
queueMessage(buffer);
queueOutMessage(Message(MessageType::HostshipRequest, buffer));
}
void ParallelConnection::resignHostship() {
std::vector<char> buffer;
queueOutMessage(Message(MessageType::HostshipResignation, buffer));
}
void ParallelConnection::setPassword(const std::string& pwd){
@@ -878,7 +837,7 @@ void ParallelConnection::setPassword(const std::string& pwd){
}
bool ParallelConnection::initNetworkAPI(){
#if defined(__WIN32__)
#if defined(WIN32)
WSADATA wsaData;
WORD version;
int error;
@@ -903,10 +862,32 @@ bool ParallelConnection::initNetworkAPI(){
return true;
}
void ParallelConnection::sendScript(const std::string& script) {
if (!_isHost) return;
network::datamessagestructures::ScriptMessage sm;
sm._script = script;
std::vector<char> buffer;
sm.serialize(buffer);
queueOutDataMessage(DataMessage(network::datamessagestructures::Type::ScriptData, buffer));
}
void ParallelConnection::preSynchronization(){
std::unique_lock<std::mutex> unqlock(_receiveBufferMutex);
while (!_receiveBuffer.empty()) {
Message& message = _receiveBuffer.front();
handleMessage(message);
_receiveBuffer.pop_front();
}
//std::cout << "start." << std::endl;
//if we're the host
if(_isHost){
/*
//get current time parameters and create a keyframe
network::datamessagestructures::TimeKeyframe tf;
tf._dt = Time::ref().deltaTime();
@@ -917,20 +898,16 @@ void ParallelConnection::preSynchronization(){
//create a buffer and serialize message
std::vector<char> tbuffer;
tf.serialize(tbuffer);
//get the size of the keyframebuffer
uint16_t msglen = static_cast<uint16_t>(tbuffer.size());
//the type of data message
uint16_t type = static_cast<uint16_t>(network::datamessagestructures::TimeData);
//create the full buffer
std::vector<char> buffer;
buffer.reserve(headerSize() + sizeof(type) + sizeof(msglen) + msglen);
//write header
writeHeader(buffer, MessageTypes::Data);
std::cout << "host 5." << std::endl;
//type of message
buffer.insert(buffer.end(), reinterpret_cast<char*>(&type), reinterpret_cast<char*>(&type) + sizeof(type));
@@ -940,10 +917,17 @@ void ParallelConnection::preSynchronization(){
//actual message
buffer.insert(buffer.end(), tbuffer.begin(), tbuffer.end());
std::cout << "host 6." << std::endl;
//send message
queueMessage(buffer);
std::cout << "pre sync queue" << std::endl;
queueMessage(MessageType::Data, buffer);
std::cout << "host 7." << std::endl;
*/
}
else{
/*
//if we're not the host and we have a valid keyframe (one that hasnt been used before)
if(_latestTimeKeyframeValid.load()){
@@ -966,11 +950,16 @@ void ParallelConnection::preSynchronization(){
Time::ref().setPause(paused);
}
*/
}
//std::cout << "stop." << std::endl;
}
void ParallelConnection::scriptMessage(const std::string propIdentifier, const std::string propValue){
//void ParallelConnection::scriptMessage(const std::string propIdentifier, const std::string propValue){
/*
//save script as current state
{
//mutex protect
@@ -1016,90 +1005,56 @@ void ParallelConnection::scriptMessage(const std::string propIdentifier, const s
//actual message
buffer.insert(buffer.end(), sbuffer.begin(), sbuffer.end());
std::cout << "script message queue" << std::endl;
//send message
queueMessage(buffer);
}
}*/
}
std::string ParallelConnection::scriptFromPropertyAndValue(const std::string property, const std::string value){
//consruct script
std::string script = "openspace.setPropertyValue(\"" + property + "\"," + value + ");";
return script;
}
//}
void ParallelConnection::broadcast(){
//while we're still connected and we're the host
while (_isConnected.load() && _isHost.load()){
while (_isConnected && _isHost) {
//create a keyframe with current position and orientation of camera
network::datamessagestructures::PositionKeyframe kf;
kf._position = OsEng.interactionHandler().camera()->position();
kf._viewRotationQuat = glm::quat_cast(glm::mat4(OsEng.interactionHandler().camera()->viewRotationMatrix()));
network::datamessagestructures::CameraKeyframe kf;
kf._position = OsEng.interactionHandler().camera()->positionVec3();
kf._rotation = OsEng.interactionHandler().camera()->rotationQuaternion();
//timestamp as current runtime of OpenSpace instance
kf._timeStamp = OsEng.runTime();
kf._timestamp = OsEng.runTime();
//create a buffer for the keyframe
std::vector<char> kfBuffer;
std::vector<char> buffer;
//fill the keyframe buffer
kf.serialize(kfBuffer);
kf.serialize(buffer);
//get the size of the keyframebuffer
uint16_t msglen = static_cast<uint16_t>(kfBuffer.size());
//the type of message
uint16_t type = static_cast<uint16_t>(network::datamessagestructures::PositionData);
//create the full buffer
std::vector<char> buffer;
buffer.reserve(headerSize() + sizeof(type) + sizeof(msglen) + msglen);
//write header
writeHeader(buffer, MessageTypes::Data);
//type of message
buffer.insert(buffer.end(), reinterpret_cast<char*>(&type), reinterpret_cast<char*>(&type) + sizeof(type));
//size of message
buffer.insert(buffer.end(), reinterpret_cast<char*>(&msglen), reinterpret_cast<char*>(&msglen) + sizeof(msglen));
//actual message
buffer.insert(buffer.end(), kfBuffer.begin(), kfBuffer.end());
//send message
queueMessage(buffer);
queueOutDataMessage(DataMessage(network::datamessagestructures::Type::CameraData, buffer));
//100 ms sleep - send keyframes 10 times per second
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
}
void ParallelConnection::writeHeader(std::vector<char> &buffer, uint32_t messageType){
//make sure the buffer is large enough to hold at least the header
if(buffer.size() < headerSize()){
buffer.reserve(headerSize());
}
//get the current running version of openspace
uint8_t versionMajor = static_cast<uint8_t>(OPENSPACE_VERSION_MAJOR);
uint8_t versionMinor = static_cast<uint8_t>(OPENSPACE_VERSION_MINOR);
//insert header into buffer
buffer.insert(buffer.end(), 'O');
buffer.insert(buffer.end(), 'S');
buffer.insert(buffer.end(), versionMajor);
buffer.insert(buffer.end(), versionMinor);
buffer.insert(buffer.end(), reinterpret_cast<char*>(&messageType), reinterpret_cast<char*>(&messageType) + sizeof(messageType));
}
int ParallelConnection::headerSize(){
//minor and major version (as uint8_t -> 1 byte) + two bytes for the chars 'O' and 'S' + 4 bytes for type of message
return 2 * sizeof(uint8_t) + 2 + sizeof(uint32_t);
}
uint32_t ParallelConnection::hash(const std::string &val) {
uint32_t hashVal = 0, i;
size_t len = val.length();
for (hashVal = i = 0; i < len; ++i) {
hashVal += val.c_str()[i];
hashVal += (hashVal << 10);
hashVal ^= (hashVal >> 6);
}
hashVal += (hashVal << 3);
hashVal ^= (hashVal >> 11);
hashVal += (hashVal << 15);
return hashVal;
};
scripting::LuaLibrary ParallelConnection::luaLibrary() {
return {
"parallel",
@@ -1146,6 +1101,12 @@ scripting::LuaLibrary ParallelConnection::luaLibrary() {
"string",
"Request to be the host for this session"
},
{
"resignHostship",
&luascriptfunctions::resignHostship,
"",
"Resign hostship"
},
}
};
}

View File

@@ -184,6 +184,17 @@ int requestHostship(lua_State* L) {
return 0;
}
int resignHostship(lua_State* L) {
int nArguments = lua_gettop(L);
if (nArguments != 0)
return luaL_error(L, "Expected %i arguments, got %i", 0, nArguments);
if (OsEng.isMaster()) {
OsEng.parallelConnection().resignHostship();
}
return 0;
}
} // namespace luascriptfunctions
} // namespace openspace

View File

@@ -52,10 +52,10 @@ void applyRegularExpression(lua_State* L, std::regex regex, std::vector<properti
//ensure properties are synced over parallel connection
std::string value;
prop->getStringValue(value);
OsEng.parallelConnection().scriptMessage(
/* OsEng.parallelConnection().scriptMessage(
prop->fullyQualifiedIdentifier(),
value
);
);*/
}
}
@@ -101,7 +101,7 @@ int property_setValueSingle(lua_State* L) {
//ensure properties are synced over parallel connection
std::string value;
prop->getStringValue(value);
OsEng.parallelConnection().scriptMessage(prop->fullyQualifiedIdentifier(), value);
//OsEng.parallelConnection().scriptMessage(prop->fullyQualifiedIdentifier(), value);
}
return 0;

View File

@@ -161,7 +161,7 @@ bool ScriptEngine::runScript(const std::string& script) {
if (OsEng.parallelConnection().isHost()) {
std::string lib, func;
if (parseLibraryAndFunctionNames(lib, func, script) && shouldScriptBeSent(lib, func)){
// OsEng.parallelConnection()->sendScript(script);
OsEng.parallelConnection().sendScript(script);
// cacheScript(lib, func, script);
}
}