mirror of
https://github.com/OpenSpace/OpenSpace.git
synced 2026-02-18 10:59:18 -06:00
begin refactor parallel connection
This commit is contained in:
@@ -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
|
||||
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -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());
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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"
|
||||
},
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user