Merge branch 'thesis/2022/software-integration_velocity-support' into thesis/2022/software-integration_dop_test

This commit is contained in:
Victor Lindquist
2022-06-14 03:07:02 -06:00
13 changed files with 623 additions and 192 deletions

View File

@@ -65,7 +65,7 @@ void NetworkEngine::stop() {
}
_incomingMessages.interrupt();
_shouldStopEventThread = true;
_socketServer.close();
_softwareConnections.clear();
@@ -90,7 +90,7 @@ void NetworkEngine::handleNewSoftwareConnections() {
socket->startStreams();
auto p = std::make_shared<SoftwareConnection>(SoftwareConnection{ std::move(socket) });
auto p = std::make_shared<SoftwareConnection>(std::move(socket));
std::lock_guard guard(_softwareConnectionsMutex);
auto [it, peerInserted] = _softwareConnections.emplace(p->id(), p);
@@ -122,7 +122,7 @@ void NetworkEngine::peerEventLoop(size_t connection_id) {
LDEBUG(fmt::format("Connection lost to {}: {}", connection_id, err.message));
_incomingMessages.push({
connection_id,
SoftwareConnection::Message{ simp::MessageType::Disconnection }
SoftwareConnection::Message{ simp::MessageType::InternalDisconnection }
});
}
break;
@@ -164,6 +164,7 @@ void NetworkEngine::handleIncomingMessage(IncomingMessage incomingMessage) {
switch (messageType) {
case simp::MessageType::Connection: {
LDEBUG(fmt::format("Message recieved... Connection: {}", incomingMessage.connection_id));
size_t offset = 0;
const std::string software = simp::readString(message, offset);
@@ -173,57 +174,63 @@ void NetworkEngine::handleIncomingMessage(IncomingMessage incomingMessage) {
break;
}
case simp::MessageType::PointData: {
LDEBUG("Message recieved.. Point data");
LDEBUG("Message recieved... Point data");
_pointDataMessageHandler.handlePointDataMessage(message, connectionPtr);
break;
}
case simp::MessageType::VelocityData: {
LDEBUG("Message recieved... Velocity data");
_pointDataMessageHandler.handleVelocityDataMessage(message, connectionPtr);
break;
}
case simp::MessageType::RemoveSceneGraphNode: {
LDEBUG(fmt::format("Message recieved.. Remove SGN"));
LDEBUG(fmt::format("Message recieved... Remove SGN"));
_pointDataMessageHandler.handleRemoveSGNMessage(message, connectionPtr);
break;
}
case simp::MessageType::Color: {
LDEBUG(fmt::format("Message recieved.. New color"));
LDEBUG(fmt::format("Message recieved... Color"));
_pointDataMessageHandler.handleFixedColorMessage(message, connectionPtr);
break;
}
case simp::MessageType::Colormap: {
LDEBUG(fmt::format("Message recieved.. New colormap"));
LDEBUG(fmt::format("Message recieved... Colormap"));
_pointDataMessageHandler.handleColormapMessage(message, connectionPtr);
break;
}
case simp::MessageType::AttributeData: {
LDEBUG(fmt::format("Message recieved.. New attribute data"));
LDEBUG(fmt::format("Message recieved... Attribute data"));
_pointDataMessageHandler.handleAttributeDataMessage(message, connectionPtr);
break;
}
case simp::MessageType::Opacity: {
LDEBUG(fmt::format("Message recieved.. New Opacity"));
LDEBUG(fmt::format("Message recieved... Opacity"));
_pointDataMessageHandler.handleOpacityMessage(message, connectionPtr);
break;
}
case simp::MessageType::FixedSize: {
LDEBUG(fmt::format("Message recieved.. New size"));
LDEBUG(fmt::format("Message recieved... Size"));
_pointDataMessageHandler.handleFixedPointSizeMessage(message, connectionPtr);
break;
}
case simp::MessageType::LinearSize: {
LDEBUG(fmt::format("Message recieved.. New linear size"));
LDEBUG(fmt::format("Message recieved... Linear size"));
_pointDataMessageHandler.handleLinearPointSizeMessage(message, connectionPtr);
break;
}
case simp::MessageType::Visibility: {
LDEBUG(fmt::format("Message recieved.. New visibility"));
LDEBUG(fmt::format("Message recieved... Visibility"));
_pointDataMessageHandler.handleVisibilityMessage(message, connectionPtr);
break;
}
case simp::MessageType::Disconnection: {
LDEBUG(fmt::format("Message recieved.. Disconnect software connection: {}", incomingMessage.connection_id));
case simp::MessageType::InternalDisconnection: {
LDEBUG(fmt::format("Message recieved... Disconnection from software connection: {}", incomingMessage.connection_id));
std::lock_guard guard(_softwareConnectionsMutex);
SoftwareConnection::NetworkEngineFriends::stopThread(connectionPtr);
if (_softwareConnections.count(incomingMessage.connection_id)) {
_softwareConnections.erase(incomingMessage.connection_id);
}
SoftwareConnection::NetworkEngineFriends::stopThread(connectionPtr);
break;
}
default: {

View File

@@ -39,7 +39,7 @@ public:
~NetworkEngine();
struct IncomingMessage {
size_t connection_id{1};
size_t connection_id;
SoftwareConnection::Message message{ softwareintegration::simp::MessageType::Unknown };
};

View File

@@ -46,7 +46,9 @@ SoftwareConnection::SoftwareConnectionLostError::SoftwareConnectionLostError(con
SoftwareConnection::SoftwareConnection(std::unique_ptr<ghoul::io::TcpSocket> socket)
: _id{ _nextConnectionId++ }, _socket{ std::move(socket) }, _sceneGraphNodes{},
_thread{}, _shouldStopThread{ false }
{}
{
LDEBUG(fmt::format("Adding software connection {}", _id));
}
SoftwareConnection::SoftwareConnection(SoftwareConnection&& sc)
: _id{ std::move(sc._id) }, _socket{ std::move(sc._socket) },
@@ -55,16 +57,17 @@ SoftwareConnection::SoftwareConnection(SoftwareConnection&& sc)
{}
SoftwareConnection::~SoftwareConnection() {
// TODO: Destructor being called on Connection for some reason
LINFO(fmt::format("Removing software connection {}", _id));
// When adding new features, always make sure that the
// destructor is called when disconnecting external
// since NetworkEngine and MessageHandler has
// shared_ptrs to SoftwareConnection, which can cause
// bugs if not handled properly.
// Tips: use weak_ptr instead of shared_ptr in callbacks.
LDEBUG(fmt::format("Removing software connection {}", _id));
if (!_isConnected) return;
_isConnected = false;
for (auto& identifier : _sceneGraphNodes) {
removePropertySubscriptions(identifier);
}
if (_socket) {
_socket->disconnect();
}
@@ -94,6 +97,8 @@ void SoftwareConnection::addPropertySubscription(
}
auto property = r->property(propertyName);
// Set new onChange handler
OnChangeHandle onChangeHandle = property->onChange(newHandler);
auto propertySubscriptions = _subscribedProperties.find(identifier);
@@ -102,7 +107,11 @@ void SoftwareConnection::addPropertySubscription(
auto propertySubscription = propertySubscriptions->second.find(propertyName);
if (propertySubscription != propertySubscriptions->second.end()) {
// Property subscription already exists
removeExistingPropertySubscription(identifier, property, propertySubscription->second);
// Remove old handle
property->removeOnChange(propertySubscription->second);
// Save new handle
propertySubscription->second = onChangeHandle;
}
else {
@@ -169,7 +178,10 @@ void SoftwareConnection::removePropertySubscriptions(const std::string& identifi
if (propertySubscriptions == _subscribedProperties.end()) return;
for (auto& [propertyName, onChangeHandle] : propertySubscriptions->second) {
auto propertySubscriptionIt = std::begin(propertySubscriptions->second);
while (propertySubscriptionIt != std::end(propertySubscriptions->second)) {
auto& [propertyName, onChangeHandle] = *propertySubscriptionIt;
if (!r->hasProperty(propertyName)) {
LWARNING(fmt::format(
"Couldn't remove property subscription. Property \"{}\" doesn't exist on \"{}\"",
@@ -178,27 +190,15 @@ void SoftwareConnection::removePropertySubscriptions(const std::string& identifi
continue;
}
auto propertySubscription = propertySubscriptions->second.find(propertyName);
if (propertySubscription == propertySubscriptions->second.end()) continue;
auto property = r->property(propertyName);
removeExistingPropertySubscription(identifier, property, onChangeHandle);
property->removeOnChange(onChangeHandle);
propertySubscriptionIt = propertySubscriptions->second.erase(propertySubscriptionIt);
}
_subscribedProperties.erase(propertySubscriptions);
}
void SoftwareConnection::removeExistingPropertySubscription(
const std::string& identifier,
properties::Property *property,
OnChangeHandle onChangeHandle
) {
property->removeOnChange(onChangeHandle);
auto propertySubscriptions = _subscribedProperties.find(identifier);
propertySubscriptions->second.erase(property->identifier());
}
void SoftwareConnection::PointDataMessageHandlerFriends::removePropertySubscription(
std::shared_ptr<SoftwareConnection> connectionPtr,
const std::string& propertyName,
@@ -230,13 +230,19 @@ void SoftwareConnection::PointDataMessageHandlerFriends::removePropertySubscript
auto propertySubscription = propertySubscriptions->second.find(propertyName);
if (propertySubscription != propertySubscriptions->second.end()) {
// Property subscription already exists
connectionPtr->removeExistingPropertySubscription(identifier, property, propertySubscription->second);
// Remove onChange handle
property->removeOnChange(propertySubscription->second);
// Remove property subscription
propertySubscriptions->second.erase(propertySubscription);
}
}
}
void SoftwareConnection::disconnect() {
_socket->disconnect();
LINFO(fmt::format("OpenSpace has disconnected with external software through socket"));
}
bool SoftwareConnection::isConnected() const {
@@ -279,11 +285,6 @@ void SoftwareConnection::removeSceneGraphNode(const std::string& identifier) {
}
}
/**
* @brief This function is only called on the server node, i.e. the node connected to the external software
*
* @return SoftwareConnection::Message
*/
SoftwareConnection::Message SoftwareConnection::receiveMessageFromSoftware() {
// Header consists of version (3 char), message type (4 char) & subject size (15 char)
size_t headerSize = 22 * sizeof(char);
@@ -325,17 +326,10 @@ SoftwareConnection::Message SoftwareConnection::receiveMessageFromSoftware() {
}
const size_t subjectSize = std::stoi(subjectSizeIn);
// TODO: Remove this
// std::string rawHeader;
// for (int i = 0; i < 22; i++) {
// rawHeader.push_back(headerBuffer[i]);
// }
// LDEBUG(fmt::format("Message received with header: {}", rawHeader));
auto typeEnum = softwareintegration::simp::getMessageType(type);
// Receive the message data
if (typeEnum != softwareintegration::simp::MessageType::Disconnection && typeEnum != softwareintegration::simp::MessageType::Unknown) {
if (typeEnum != softwareintegration::simp::MessageType::InternalDisconnection && typeEnum != softwareintegration::simp::MessageType::Unknown) {
subjectBuffer.resize(subjectSize);
if (!_socket->get(subjectBuffer.data(), subjectSize)) {
throw SoftwareConnectionLostError("Failed to read message from socket. Disconnecting.");

View File

@@ -104,11 +104,6 @@ public:
private:
void removePropertySubscriptions(const std::string& identifier);
void removeExistingPropertySubscription(
const std::string& identifier,
properties::Property *property,
OnChangeHandle onChangeHandle
);
SubscribedProperties _subscribedProperties;

View File

@@ -33,6 +33,7 @@
#include <openspace/rendering/renderable.h>
#include <openspace/rendering/renderengine.h>
#include <openspace/scene/scene.h>
#include <openspace/util/distanceconstants.h>
#include <openspace/scripting/scriptengine.h>
#include <ghoul/logging/logmanager.h>
#include <ghoul/misc/dictionaryluaformatter.h>
@@ -85,6 +86,102 @@ void PointDataMessageHandler::handlePointDataMessage(const std::vector<char>& me
addCallback(identifier, { reanchorCallback, { storage::Key::DataPoints }, "reanchorCallback" });
}
void PointDataMessageHandler::handleVelocityDataMessage(const std::vector<char>& message, std::shared_ptr<SoftwareConnection> connection) {
LWARNING(fmt::format("PointDataMessageHandler::handleVelocityDataMessage()"));
size_t messageOffset = 0;
std::string identifier;
checkRenderable(message, messageOffset, connection, identifier);
simp::LengthUnit length_unit;
simp::NaNRenderMode velNaNMode;
glm::vec4 velNaNColor;
size_t nVelocities;
size_t dimensionality;
std::vector<float> velocities;
try {
// The following order of creating variables is the exact order they are received
// in the message. If the order is not the same, the global variable
// 'message offset' will be wrong
length_unit = simp::getLengthUnit(simp::readString(message, messageOffset));
if (length_unit == simp::LengthUnit::Unknown) {
// TODO: Write message
throw simp::SimpError("");
}
velNaNMode = simp::getNaNRenderMode(simp::readString(message, messageOffset));
switch (velNaNMode) {
case simp::NaNRenderMode::Color:
velNaNColor = simp::readColor(message, messageOffset);
break;
case simp::NaNRenderMode::Hide: // Nothing to read
break;
default: // simp::NaNRenderMode::Unknown
// TODO: Write message
throw simp::SimpError("");
break;
}
nVelocities = static_cast<size_t>(simp::readIntValue(message, messageOffset));
dimensionality = static_cast<size_t>(simp::readIntValue(message, messageOffset));
simp::readPointData(message, messageOffset, nVelocities, dimensionality, velocities);
}
catch (const simp::SimpError& err) {
LERROR(fmt::format("Error when reading point data message: {}", err.message));
return;
}
// Convert data to m/s (assuming time unit is seconds for now)
if (length_unit != simp::LengthUnit::m) {
convertToMeterPerSecond(length_unit, velocities);
}
// Use the renderable identifier as the data key
auto module = global::moduleEngine->module<SoftwareIntegrationModule>();
module->storeData(identifier, storage::Key::VelocityData, std::move(velocities));
auto velNaNModeCallback = [this, identifier, velNaNMode, velNaNColor, connection] {
if (velNaNMode == simp::NaNRenderMode::Color) {
// Get renderable
auto r = getRenderable(identifier);
// Get velNaNColor of renderable
properties::Property* velNaNColorProperty = r->property("VelNaNColor");
glm::vec4 propertyVelNaNColor = std::any_cast<glm::vec4>(velNaNColorProperty->get());
// Update velNaNColor of renderable
if (propertyVelNaNColor != velNaNColor) {
global::scriptEngine->queueScript(
fmt::format(
"openspace.setPropertyValueSingle('Scene.{}.Renderable.VelNaNColor', {});",
identifier, ghoul::to_string(velNaNColor)
),
scripting::ScriptEngine::RemoteScripting::Yes
);
}
}
global::scriptEngine->queueScript(
fmt::format(
"openspace.setPropertyValueSingle('Scene.{}.Renderable.VelNaNMode', {});",
identifier, static_cast<int>(velNaNMode)
),
scripting::ScriptEngine::RemoteScripting::Yes
);
};
addCallback(identifier, { velNaNModeCallback, {}, "velNaNModeCallback" });
auto enableMotionCallback = [identifier] {
global::scriptEngine->queueScript(
fmt::format(
"openspace.setPropertyValueSingle('Scene.{}.Renderable.MotionEnabled', {});",
identifier, "true"
),
scripting::ScriptEngine::RemoteScripting::Yes
);
};
addCallback(identifier, { enableMotionCallback, { storage::Key::VelocityData }, "Enable motion mode, wait for VelocityData" });
}
void PointDataMessageHandler::handleFixedColorMessage(const std::vector<char>& message, std::shared_ptr<SoftwareConnection> connection) {
size_t messageOffset = 0;
std::string identifier;
@@ -100,13 +197,19 @@ void PointDataMessageHandler::handleFixedColorMessage(const std::vector<char>& m
return;
}
auto callback = [this, identifier, color, connection] {
// Get renderable
auto r = getRenderable(identifier);
// Get renderable
auto r = getRenderable(identifier);
if (!r) return;
// Get color of renderable
properties::Property* colorProperty = r->property("Color");
glm::vec4 propertyColor = std::any_cast<glm::vec4>(colorProperty->get());
// Get color of renderable
properties::Property* colorProperty = r->property("Color");
// Create weak_ptr, safer than shared_ptr for lambdas
std::weak_ptr<SoftwareConnection> connWeakPtr{ connection };
auto setFixedColorCallback = [this, identifier, color, colorProperty, connWeakPtr] {
if (!colorProperty || connWeakPtr.expired()) return;
// auto conn = connWeakPtr.lock()
// auto propertySub = connection->getPropertySubscription(identifier, colorProperty->identifier());
// if (propertySub) {
@@ -114,7 +217,8 @@ void PointDataMessageHandler::handleFixedColorMessage(const std::vector<char>& m
// }
// Update color of renderable
if (propertyColor != color) {
glm::vec4 currentColor = std::any_cast<glm::vec4>(colorProperty->get());
if (currentColor != color) {
global::scriptEngine->queueScript(
fmt::format(
"openspace.setPropertyValueSingle('Scene.{}.Renderable.Color', {});",
@@ -132,7 +236,14 @@ void PointDataMessageHandler::handleFixedColorMessage(const std::vector<char>& m
scripting::ScriptEngine::RemoteScripting::Yes
);
};
addCallback(identifier, { callback, {}, "handleFixedColorMessage" });
addCallback(identifier, { setFixedColorCallback, {}, "handleFixedColorMessage" });
// Create and set onChange for color
auto updateColor = [this, colorProperty, identifier, connWeakPtr] {
if (!colorProperty || connWeakPtr.expired()) return;
onFixedColorChange(colorProperty, identifier, connWeakPtr.lock());
};
connection->addPropertySubscription(colorProperty->identifier(), identifier, updateColor);
}
void PointDataMessageHandler::handleColormapMessage(const std::vector<char>& message, std::shared_ptr<SoftwareConnection> connection) {
@@ -143,22 +254,23 @@ void PointDataMessageHandler::handleColormapMessage(const std::vector<char>& mes
float min;
float max;
simp::CmapNaNMode cmapNaNMode;
simp::NaNRenderMode cmapNaNMode;
glm::vec4 cmapNaNColor;
size_t nColors;
std::vector<float> colorMap;
try {
min = simp::readFloatValue(message, messageOffset);
max = simp::readFloatValue(message, messageOffset);
cmapNaNMode = simp::getCmapNaNMode(simp::readString(message, messageOffset));
cmapNaNMode = simp::getNaNRenderMode(simp::readString(message, messageOffset));
switch (cmapNaNMode) {
case simp::CmapNaNMode::Color:
case simp::NaNRenderMode::Color:
cmapNaNColor = simp::readColor(message, messageOffset);
break;
case simp::CmapNaNMode::Hide: // Nothing to read
case simp::NaNRenderMode::Hide: // Nothing to read
break;
default: // simp::CmapNaNMode::Unknown
// TODO: Throw SimpError
default: // simp::NaNRenderMode::Unknown
// TODO: Write message
throw simp::SimpError("");
break;
}
nColors = static_cast<size_t>(simp::readIntValue(message, messageOffset));
@@ -213,8 +325,7 @@ void PointDataMessageHandler::handleColormapMessage(const std::vector<char>& mes
addCallback(identifier, { colormapLimitsCallback, {}, "colormapLimitsCallback" });
auto cmapNaNModeCallback = [this, identifier, cmapNaNMode, cmapNaNColor, connection] {
if (cmapNaNMode == simp::CmapNaNMode::Color) {
if (cmapNaNMode == simp::NaNRenderMode::Color) {
// Get renderable
auto r = getRenderable(identifier);
@@ -343,14 +454,20 @@ void PointDataMessageHandler::handleOpacityMessage(const std::vector<char>& mess
return;
}
auto callback = [this, identifier, opacity, connection] {
// Get renderable
auto r = getRenderable(identifier);
// Get renderable
auto r = getRenderable(identifier);
if (!r) return;
// Get opacity of renderable
properties::Property* opacityProperty = r->property("Opacity");
// Create weak_ptr, safer than shared_ptr for lambdas
std::weak_ptr<SoftwareConnection> connWeakPtr{ connection };
// Get opacity from renderable
properties::Property* opacityProperty = r->property("Opacity");
auto propertyAny = opacityProperty->get();
float propertyOpacity = std::any_cast<float>(propertyAny);
auto callback = [this, identifier, opacity, opacityProperty, connWeakPtr] {
if (!opacityProperty || connWeakPtr.expired()) return;
// auto conn = connWeakPtr.lock()
// auto propertySub = connection->getPropertySubscription(identifier, opacityProperty->identifier());
// if (propertySub) {
@@ -358,7 +475,8 @@ void PointDataMessageHandler::handleOpacityMessage(const std::vector<char>& mess
// }
// Update opacity of renderable
if (propertyOpacity != opacity) {
float currentOpacity = std::any_cast<float>(opacityProperty->get());
if (currentOpacity != opacity) {
std::string script = fmt::format(
"openspace.setPropertyValueSingle('Scene.{}.Renderable.Opacity', {});",
identifier, ghoul::to_string(opacity)
@@ -370,6 +488,13 @@ void PointDataMessageHandler::handleOpacityMessage(const std::vector<char>& mess
}
};
addCallback(identifier, { callback, {}, "handleOpacityMessage" });
// Create and set onChange for opacity
auto updateOpacity = [this, opacityProperty, identifier, connWeakPtr] {
if (!opacityProperty || connWeakPtr.expired()) return;
onOpacityChange(opacityProperty, identifier, connWeakPtr.lock());
};
connection->addPropertySubscription(opacityProperty->identifier(), identifier, updateOpacity);
}
void PointDataMessageHandler::handleFixedPointSizeMessage(const std::vector<char>& message, std::shared_ptr<SoftwareConnection> connection) {
@@ -387,14 +512,19 @@ void PointDataMessageHandler::handleFixedPointSizeMessage(const std::vector<char
return;
}
auto callback = [this, identifier, size, connection] {
// Get renderable
auto r = getRenderable(identifier);
// Get renderable
auto r = getRenderable(identifier);
if (!r) return;
// Get size from renderable
properties::Property* sizeProperty = r->property("Size");
auto propertyAny = sizeProperty->get();
float propertySize = std::any_cast<float>(propertyAny);
// Get size of renderable
properties::Property* sizeProperty = r->property("Size");
// Create weak_ptr, safer than shared_ptr for lambdas
std::weak_ptr<SoftwareConnection> connWeakPtr{ connection };
auto callback = [this, identifier, size, sizeProperty, connWeakPtr] {
if (!sizeProperty || connWeakPtr.expired()) return;
// auto conn = connWeakPtr.lock()
// auto propertySub = connection->getPropertySubscription(identifier, sizeProperty->identifier());
// if (propertySub) {
@@ -402,7 +532,8 @@ void PointDataMessageHandler::handleFixedPointSizeMessage(const std::vector<char
// }
// Update size of renderable
if (propertySize != size) {
float currentSize = std::any_cast<float>(sizeProperty->get());
if (currentSize != size) {
// TODO: Add interpolation to script, but do not send back
// updates to external software until the interpolation is done
// Use this: "openspace.setPropertyValueSingle('Scene.{}.Renderable.Size', {}, 1);",
@@ -424,6 +555,12 @@ void PointDataMessageHandler::handleFixedPointSizeMessage(const std::vector<char
);
};
addCallback(identifier, { callback, {}, "handleFixedPointSizeMessage" });
auto updateSize = [this, sizeProperty, identifier, connWeakPtr] {
if (!sizeProperty || connWeakPtr.expired()) return;
onFixedPointSizeChange(sizeProperty, identifier, connWeakPtr.lock());
};
connection->addPropertySubscription(sizeProperty->identifier(), identifier, updateSize);
}
void PointDataMessageHandler::handleLinearPointSizeMessage(const std::vector<char>& message, std::shared_ptr<SoftwareConnection> connection) {
@@ -525,9 +662,21 @@ void PointDataMessageHandler::handleVisibilityMessage(const std::vector<char>& m
return;
}
auto callback = [this, identifier, visibilityMessage, connection] {
// Get renderable
// auto r = getRenderable(identifier);
// Get renderable
auto r = getRenderable(identifier);
if (!r) return;
// Get visibility of renderable
properties::Property* visibilityProperty = r->property("Enabled");
// Create weak_ptr, safer than shared_ptr for lambdas
std::weak_ptr<SoftwareConnection> connWeakPtr{ connection };
const bool visibility = visibilityMessage == "T";
auto callback = [this, identifier, visibility, visibilityProperty, connWeakPtr] {
if (!visibilityProperty || connWeakPtr.expired()) return;
// auto conn = connWeakPtr.lock()
// Get visibility from renderable
// properties::Property* enabledProperty = r->property("Enabled");
@@ -536,18 +685,28 @@ void PointDataMessageHandler::handleVisibilityMessage(const std::vector<char>& m
// propertySub->shouldSendMessage = false;
// }
// Toggle visibility from renderable
const std::string visability = visibilityMessage == "T" ? "true" : "false";
std::string script = fmt::format(
"openspace.setPropertyValueSingle('Scene.{}.Renderable.Enabled', {});",
identifier, visability
);
global::scriptEngine->queueScript(
script,
scripting::ScriptEngine::RemoteScripting::Yes
);
// Toggle visibility of renderable
bool currentVisibility = std::any_cast<bool>(visibilityProperty->get());
if (currentVisibility != visibility) {
const std::string vis = visibility ? "true" : "false";
std::string script = fmt::format(
"openspace.setPropertyValueSingle('Scene.{}.Renderable.Enabled', {});",
identifier, vis
);
global::scriptEngine->queueScript(
script,
scripting::ScriptEngine::RemoteScripting::Yes
);
}
};
addCallback(identifier, { callback, {}, "handleVisibilityMessage" });
// Create and set onChange for visibility
auto toggleVisibility = [this, visibilityProperty, identifier, connWeakPtr] {
if (!visibilityProperty || connWeakPtr.expired()) return;
onVisibilityChange(visibilityProperty, identifier, connWeakPtr.lock());
};
connection->addPropertySubscription(visibilityProperty->identifier(), identifier, toggleVisibility);
}
void PointDataMessageHandler::handleRemoveSGNMessage(const std::vector<char>& message,std::shared_ptr<SoftwareConnection> connection) {
@@ -689,66 +848,6 @@ void PointDataMessageHandler::checkRenderable(
"openspace.setPropertyValueSingle('Modules.CefWebGui.Reload', nil)", // Reload WebGUI so that SoftwareIntegration GUI appears
scripting::ScriptEngine::RemoteScripting::Yes
);
auto subscriptionCallback = [this, identifier, connection] {
subscribeToRenderableUpdates(identifier, connection);
};
addCallback(identifier, { subscriptionCallback, {}, "subscriptionCallback" });
}
else {
subscribeToRenderableUpdates(identifier, connection);
}
}
void PointDataMessageHandler::subscribeToRenderableUpdates(
const std::string& identifier,
std::shared_ptr<SoftwareConnection> connection
) {
// Get renderable
auto aRenderable = getRenderable(identifier);
if (!aRenderable) return;
if (!connection->isConnected()) {
LERROR(fmt::format(
"Could not subscribe to updates for renderable '{}' due to lost connection",
identifier
));
return;
}
// Update color of renderable
properties::Property* colorProperty = aRenderable->property("Color");
if (colorProperty) {
auto updateColor = [this, colorProperty, identifier, connection]() {
onFixedColorChange(colorProperty, identifier, connection);
};
connection->addPropertySubscription(colorProperty->identifier(), identifier, updateColor);
}
// Update opacity of renderable
properties::Property* opacityProperty = aRenderable->property("Opacity");
if (opacityProperty) {
auto updateOpacity = [this, opacityProperty, identifier, connection]() {
onOpacityChange(opacityProperty, identifier, connection);
};
connection->addPropertySubscription(opacityProperty->identifier(), identifier, updateOpacity);
}
// Update size of renderable
properties::Property* sizeProperty = aRenderable->property("Size");
if (sizeProperty) {
auto updateSize = [this, sizeProperty, identifier, connection] {
onFixedPointSizeChange(sizeProperty, identifier, connection);
};
connection->addPropertySubscription(sizeProperty->identifier(), identifier, updateSize);
}
// Toggle visibility of renderable
properties::Property* visibilityProperty = aRenderable->property("Enabled");
if (visibilityProperty) {
auto toggleVisibility = [this, visibilityProperty, identifier, connection] {
onVisibilityChange(visibilityProperty, identifier, connection);
};
connection->addPropertySubscription(visibilityProperty->identifier(), identifier, toggleVisibility);
}
}
@@ -870,4 +969,35 @@ void PointDataMessageHandler::onVisibilityChange(
connection->sendMessage(message);
}
// TODO: Move to SIMP / use distanceconversion
void PointDataMessageHandler::convertToMeterPerSecond(simp::LengthUnit currLengthUnit, std::vector<float>& data) {
// distanceconversion::convertDistance
float multiplier = 1.0;
switch (currLengthUnit) {
case simp::LengthUnit::km:
multiplier = 1000.0;
break;
case simp::LengthUnit::AU:
multiplier = static_cast<float>(distanceconstants::AstronomicalUnit);
break;
case simp::LengthUnit::lyr:
multiplier = static_cast<float>(distanceconstants::LightYear);
break;
case simp::LengthUnit::pc:
multiplier = static_cast<float>(distanceconstants::Parsec);
break;
case simp::LengthUnit::kpc:
multiplier = static_cast<float>(distanceconstants::Parsec * 1.0e3);
break;
case simp::LengthUnit::Mpc:
multiplier = static_cast<float>(distanceconstants::Parsec * 1.0e6);
break;
default:
break;
}
std::transform(std::begin(data), std::end(data), std::begin(data),
[multiplier] (float f) {return f * multiplier;});
}
} // namespace openspace

View File

@@ -46,6 +46,7 @@ class PointDataMessageHandler {
public:
void handlePointDataMessage(const std::vector<char>& message, std::shared_ptr<SoftwareConnection> connection);
void handleVelocityDataMessage(const std::vector<char>& message, std::shared_ptr<SoftwareConnection> connection);
void handleFixedColorMessage(const std::vector<char>& message, std::shared_ptr<SoftwareConnection> connection);
void handleColormapMessage(const std::vector<char>& message, std::shared_ptr<SoftwareConnection> connection);
void handleAttributeDataMessage(const std::vector<char>& message, std::shared_ptr<SoftwareConnection> connection);
@@ -64,8 +65,6 @@ private:
std::shared_ptr<SoftwareConnection> connection, std::string& identifier
);
void subscribeToRenderableUpdates(const std::string& identifier, std::shared_ptr<SoftwareConnection> connection);
void addCallback(
const std::string& identifier,
const Callback& newCallback
@@ -95,6 +94,11 @@ private:
const std::string& identifier,
std::shared_ptr<SoftwareConnection> connection
);
void convertToMeterPerSecond(
softwareintegration::simp::LengthUnit currLengthUnit,
std::vector<float>& data
);
};
} // namespace openspace

View File

@@ -42,16 +42,19 @@
#include <ghoul/opengl/textureunit.h>
#include <fstream>
int TIME_COUNTER = 0;
namespace {
constexpr const char* _loggerCat = "PointsCloud";
constexpr const std::array<const char*, 18> UniformNames = {
constexpr const std::array<const char*, 20> UniformNames = {
"color", "opacity", "size", "modelMatrix", "cameraUp", "screenSize",
"cameraViewProjectionMatrix", "eyePosition", "sizeOption",
"colormapTexture", "colormapMin", "colormapMax", "cmapNaNMode",
"cmapNaNColor", "colormapEnabled", "linearSizeMin", "linearSizeMax",
"linearSizeEnabled"
"linearSizeEnabled", "motionEnabled", "theTime"
};
// "velNaNMode", "velNaNColor",
constexpr openspace::properties::Property::PropertyInfo ColorInfo = {
"Color",
@@ -130,6 +133,24 @@ namespace {
"Linear size enabled",
"Boolean to determine whether to use linear size or not."
};
constexpr openspace::properties::Property::PropertyInfo VelNaNModeInfo = {
"VelNaNMode",
"Vel NaN Mode",
"How points with NaN value in colormap attribute should be represented."
};
constexpr openspace::properties::Property::PropertyInfo VelNaNColorInfo = {
"VelNaNColor",
"Vel NaN Color",
"The color of the points where the colormap scalar is NaN."
};
constexpr openspace::properties::Property::PropertyInfo MotionEnabledInfo = {
"MotionEnabled",
"Motion enabled",
"Boolean to determine whether to use motion or not."
};
constexpr openspace::properties::Property::PropertyInfo NameInfo = {
"Name",
@@ -144,6 +165,7 @@ namespace {
// [[codegen::verbatim(SizeInfo.description)]]
std::optional<float> size;
// TODO: This can be removed? Not in use anymore?
// [[codegen::verbatim(DataInfo.description)]]
std::optional<std::vector<glm::vec3>> data;
@@ -177,6 +199,15 @@ namespace {
// [[codegen::verbatim(NameInfo.description)]]
std::optional<std::string> name;
// [[codegen::verbatim(VelNaNModeInfo.description)]]
std::optional<int> velNaNMode;
// [[codegen::verbatim(VelNaNColorInfo.description)]]
std::optional<glm::vec4> velNaNColor;
// [[codegen::verbatim(MotionEnabledInfo.description)]]
std::optional<bool> motionEnabled;
enum class SizeOption : uint32_t {
Uniform,
NonUniform
@@ -207,8 +238,11 @@ RenderablePointsCloud::RenderablePointsCloud(const ghoul::Dictionary& dictionary
, _colormapEnabled(ColormapEnabledInfo, false)
, _linearSizeMax(LinearSizeMinInfo)
, _linearSizeMin(LinearSizeMaxInfo)
, _linearSizeEnabled(LinearSizeEnabledInfo)
, _linearSizeEnabled{LinearSizeEnabledInfo, false}
, _name(NameInfo)
, _velNaNMode(VelNaNModeInfo)
, _velNaNColor(VelNaNColorInfo, glm::vec4(glm::vec3(0.5f), 1.f), glm::vec4(1.0f), glm::vec4(0.f), glm::vec4(0.f))
, _motionEnabled(MotionEnabledInfo, false)
{
const Parameters p = codegen::bake<Parameters>(dictionary);
@@ -289,6 +323,19 @@ RenderablePointsCloud::RenderablePointsCloud(const ghoul::Dictionary& dictionary
_linearSizeMax.setVisibility(properties::Property::Visibility::Hidden);
_linearSizeMax.onChange(linearSizeMinMaxChecker);
addProperty(_linearSizeMax);
_velNaNMode = p.velNaNMode.value_or(_velNaNMode);
_velNaNMode.setVisibility(properties::Property::Visibility::Hidden);
addProperty(_velNaNMode);
_velNaNColor = p.velNaNColor.value_or(_velNaNColor);
// _velNaNColor.setViewOption(properties::Property::ViewOptions::Color); // TODO: CHECK WHAT THIS IS
_velNaNColor.setVisibility(properties::Property::Visibility::Hidden);
addProperty(_velNaNColor);
_motionEnabled = p.motionEnabled.value_or(_motionEnabled);
_motionEnabled.onChange([this] { checkIfMotionCanBeEnabled(); });
addProperty(_motionEnabled);
}
bool RenderablePointsCloud::isReady() const {
@@ -381,6 +428,14 @@ void RenderablePointsCloud::render(const RenderData& data, RendererTasks&) {
_shaderProgram->setUniform(_uniformCache.linearSizeMax, _linearSizeMax);
_shaderProgram->setUniform(_uniformCache.linearSizeEnabled, _linearSizeEnabled);
// _shaderProgram->setUniform(_uniformCache.velNaNMode, _velNaNMode);
// _shaderProgram->setUniform(_uniformCache.velNaNColor, _velNaNColor);
_shaderProgram->setUniform(_uniformCache.motionEnabled, _motionEnabled);
_shaderProgram->setUniform(
_uniformCache.theTime,
static_cast<float>(data.time.j2000Seconds())
);
_shaderProgram->setUniform(_uniformCache.color, _color);
_shaderProgram->setUniform(_uniformCache.opacity, _opacity);
@@ -429,6 +484,7 @@ void RenderablePointsCloud::update(const UpdateData&) {
auto pointDataSlice = getDataSlice(DataSliceKey::Points);
auto colormapAttrDataSlice = getDataSlice(DataSliceKey::ColormapAttributes);
auto linearSizeAttrDataSlice = getDataSlice(DataSliceKey::LinearSizeAttributes);
auto velocityDataSlice = getDataSlice(DataSliceKey::Velocity);
if (pointDataSlice->empty()) return;
@@ -445,14 +501,28 @@ void RenderablePointsCloud::update(const UpdateData&) {
bufferData.push_back(colormapAttrDataSlice->at(i));
}
else {
bufferData.push_back(0.0);
bufferData.push_back(0.0); // TODO: We might not want to put 0.0 here. How is this rendered?
}
if (linearSizeAttrDataSlice->size() > i) {
bufferData.push_back(linearSizeAttrDataSlice->at(i));
}
else {
bufferData.push_back(0.0);
bufferData.push_back(0.0); // TODO: We might not want to put 0.0 here. How is this rendered?
}
if (velocityDataSlice->size() > (j + 2)) {
bufferData.push_back(velocityDataSlice->at(j));
bufferData.push_back(velocityDataSlice->at(j + 1));
bufferData.push_back(velocityDataSlice->at(j + 2));
}
else {
bufferData.push_back(std::nanf("0")); // TODO: We might not want to put 0.0 here. How is this rendered? Maybe push NAN?
bufferData.push_back(std::nanf("0")); // TODO: We might not want to put 0.0 here. How is this rendered? Maybe push NAN?
bufferData.push_back(std::nanf("0")); // TODO: We might not want to put 0.0 here. How is this rendered? Maybe push NAN?
// bufferData.push_back(0.0); // TODO: We might not want to put 0.0 here. How is this rendered? Maybe push NAN?
// bufferData.push_back(0.0); // TODO: We might not want to put 0.0 here. How is this rendered? Maybe push NAN?
// bufferData.push_back(0.0); // TODO: We might not want to put 0.0 here. How is this rendered? Maybe push NAN?
}
}
@@ -465,7 +535,7 @@ void RenderablePointsCloud::update(const UpdateData&) {
// ==============================================================================================
// ========================================= VAO stuff =========================================
GLsizei stride = static_cast<GLsizei>(sizeof(GLfloat) * 5);
GLsizei stride = static_cast<GLsizei>(sizeof(GLfloat) * _nValuesForVAOStride);
GLint positionAttribute = _shaderProgram->attributeLocation("in_position");
glEnableVertexAttribArray(positionAttribute);
glVertexAttribPointer(
@@ -502,6 +572,19 @@ void RenderablePointsCloud::update(const UpdateData&) {
reinterpret_cast<void*>(sizeof(GLfloat) * 4)
);
}
if (_hasLoadedVelocityData) {
GLint velocityAttribute = _shaderProgram->attributeLocation("in_velocity");
glEnableVertexAttribArray(velocityAttribute);
glVertexAttribPointer(
velocityAttribute,
3,
GL_FLOAT,
GL_FALSE,
stride,
reinterpret_cast<void*>(sizeof(GLfloat) * 5)
);
}
// ==============================================================================================
glBindBuffer(GL_ARRAY_BUFFER, 0);
@@ -536,6 +619,11 @@ bool RenderablePointsCloud::checkDataStorage() {
loadLinearSizeAttributeData(softwareIntegrationModule);
updatedDataSlices = true;
}
if (softwareIntegrationModule->isDataDirty(_identifier.value(), storage::Key::VelocityData)) {
loadVelocityData(softwareIntegrationModule);
updatedDataSlices = true;
}
return updatedDataSlices;
}
@@ -551,7 +639,7 @@ void RenderablePointsCloud::loadData(SoftwareIntegrationModule* softwareIntegrat
auto pointDataSlice = getDataSlice(DataSliceKey::Points);
pointDataSlice->clear();
pointDataSlice->reserve(fullPointData.size() * 3);
pointDataSlice->reserve(fullPointData.size() * 3); // TODO: Do we really need *3 here?
// Create data slice
auto addPosition = [&](const glm::vec4& pos) {
@@ -630,7 +718,7 @@ void RenderablePointsCloud::loadCmapAttributeData(SoftwareIntegrationModule* sof
}
_hasLoadedColormapAttributeData = true;
LDEBUG("Rerendering colormap attribute data");
LDEBUG("Rerendering with colormap attribute data");
}
void RenderablePointsCloud::loadLinearSizeAttributeData(SoftwareIntegrationModule* softwareIntegrationModule) {
@@ -648,7 +736,7 @@ void RenderablePointsCloud::loadLinearSizeAttributeData(SoftwareIntegrationModul
"There is a mismatch in the amount of linear size attribute scalars ({}) and the amount of points ({})",
linearSizeAttributeData.size(), pointDataSlice->size() / 3
));
_colormapEnabled = false;
_linearSizeEnabled = false;
return;
}
@@ -661,9 +749,108 @@ void RenderablePointsCloud::loadLinearSizeAttributeData(SoftwareIntegrationModul
}
_hasLoadedLinearSizeAttributeData = true;
LDEBUG("Rerendering linear size attribute data");
LDEBUG("Rerendering with linear size attribute data");
}
void RenderablePointsCloud::loadVelocityData(SoftwareIntegrationModule* softwareIntegrationModule) {
// Fetch data from module's centralized storage
auto velocityData = softwareIntegrationModule->fetchData(_identifier.value(), storage::Key::VelocityData);
if (velocityData.empty()) {
LWARNING("There was an issue trying to fetch the velocity data from the centralized storage.");
return;
}
auto pointDataSlice = getDataSlice(DataSliceKey::Points);
if (pointDataSlice->size() != velocityData.size()) {
LWARNING(fmt::format(
"There is a mismatch in the amount of velocity data ({}) and the amount of points ({})",
velocityData.size() / 3, pointDataSlice->size() / 3
));
_motionEnabled = false;
return;
}
auto velocityDataSlice = getDataSlice(DataSliceKey::Velocity);
velocityDataSlice->clear();
velocityDataSlice->reserve(velocityData.size() * 3); // TODO: Do we really need *3 here?
// =========================================
int nNans = 0;
int prevNNans = 0;
int nPointsContainingNans = 0;
// Create velocity data slice
auto addPosition = [&](const glm::vec4& pos) {
for (glm::vec4::length_type j = 0; j < glm::vec4::length() - 1; ++j) {
if (isnan(pos[j])) {
nNans++;
}
velocityDataSlice->push_back(pos[j]);
}
if (prevNNans < nNans) {
nPointsContainingNans++;
prevNNans = nNans;
}
};
for (size_t i = 0; i < velocityData.size(); i += 3) {
glm::dvec4 transformedPos = {
velocityData[i + 0],
velocityData[i + 1],
velocityData[i + 2],
1.0
};
// W-normalization
// transformedPos /= transformedPos.w;
// transformedPos *= distanceconstants::Parsec; // TODO: Is this converting parsec => meter?
addPosition(transformedPos);
}
LWARNING(fmt::format("Points: {}. Velocity points: {}. Velocity points w/ nans {}. Velocity nans in total: {}", pointDataSlice->size()/3, velocityData.size()/3, nPointsContainingNans, nNans));
// =========================================
_hasLoadedVelocityData = true;
LDEBUG("Rerendering with motion based on velocity data");
}
// void RenderablePointsCloud::loadData(SoftwareIntegrationModule* softwareIntegrationModule) {
// // Fetch data from module's centralized storage
// auto fullPointData = softwareIntegrationModule->fetchData(_identifier.value(), storage::Key::DataPoints);
// if (fullPointData.empty()) {
// LWARNING("There was an issue trying to fetch the point data from the centralized storage.");
// return;
// }
// auto pointDataSlice = getDataSlice(DataSliceKey::Points);
// pointDataSlice->clear();
// pointDataSlice->reserve(fullPointData.size() * 3);
// // Create data slice
// auto addPosition = [&](const glm::vec4& pos) {
// for (glm::vec4::length_type j = 0; j < glm::vec4::length() - 1; ++j) {
// pointDataSlice->push_back(pos[j]);
// }
// };
// for (size_t i = 0; i < fullPointData.size(); i += 3) {
// glm::dvec4 transformedPos = {
// fullPointData[i + 0],
// fullPointData[i + 1],
// fullPointData[i + 2],
// 1.0
// };
// // W-normalization
// transformedPos /= transformedPos.w;
// transformedPos *= distanceconstants::Parsec;
// addPosition(transformedPos);
// }
// }
std::shared_ptr<RenderablePointsCloud::DataSlice> RenderablePointsCloud::getDataSlice(DataSliceKey key) {
if (!_dataSlices.count(key)) {
_dataSlices.insert({ key, std::make_shared<DataSlice>() });
@@ -713,6 +900,24 @@ void RenderablePointsCloud::checkIfLinearSizeCanBeEnabled() {
}
}
void RenderablePointsCloud::checkIfMotionCanBeEnabled() {
if (!global::windowDelegate->isMaster()) return;
// This can happen if the user checks the "MotionEnabled" checkbox in the GUI
auto velocityData = getDataSlice(DataSliceKey::Velocity);
if (_motionEnabled.value() && velocityData->empty()) {
LINFO("Velocity data not loaded. Has it been sent from external software?");
global::scriptEngine->queueScript(
fmt::format(
"openspace.setPropertyValueSingle('Scene.{}.Renderable.MotionEnabled', {});",
_identifier.value(), "false"
),
scripting::ScriptEngine::RemoteScripting::Yes
);
}
LINFO(fmt::format("checkIfMotionCanBeEnabled(): MotionEnabled = {}", _motionEnabled));
}
void RenderablePointsCloud::checkColormapMinMax() {
float min = std::any_cast<float>(_colormapMin.get());
float max = std::any_cast<float>(_colormapMax.get());

View File

@@ -67,12 +67,14 @@ private:
void loadColormap(SoftwareIntegrationModule* softwareIntegrationModule);
void loadCmapAttributeData(SoftwareIntegrationModule* softwareIntegrationModule);
void loadLinearSizeAttributeData(SoftwareIntegrationModule* softwareIntegrationModule);
void loadVelocityData(SoftwareIntegrationModule* softwareIntegrationModule);
bool checkDataStorage();
void checkColormapMinMax();
void checkIfColormapCanBeEnabled();
void checkIfLinearSizeCanBeEnabled();
void checkColormapMinMax();
void checkIfMotionCanBeEnabled();
std::unique_ptr<ghoul::opengl::ProgramObject> _shaderProgram = nullptr;
UniformCache(
@@ -80,8 +82,9 @@ private:
cameraViewProjectionMatrix, eyePosition, sizeOption,
colormapTexture, colormapMin, colormapMax, cmapNaNMode,
cmapNaNColor, colormapEnabled, linearSizeMin, linearSizeMax,
linearSizeEnabled
linearSizeEnabled,motionEnabled, theTime
) _uniformCache;
// velNaNMode, velNaNColor,
properties::FloatProperty _size;
properties::Vec4Property _color;
@@ -98,17 +101,27 @@ private:
properties::Vec4Property _cmapNaNColor;
properties::StringProperty _name;
properties::BoolProperty _motionEnabled;
properties::IntProperty _velNaNMode;
properties::Vec4Property _velNaNColor;
std::optional<std::string> _identifier = std::nullopt;
bool _hasLoadedColormapAttributeData = false;
bool _hasLoadedColormap = false;
bool _hasLoadedLinearSizeAttributeData = false;
bool _hasLoadedVelocityData = false;
// This is determined by nrAttributes + size for each attribute
const size_t _nValuesForVAOStride = 8;
enum class DataSliceKey : size_t {
Points = 0,
ColormapAttributes,
LinearSizeAttributes
LinearSizeAttributes,
Velocity
};
using DataSlice = std::vector<float>;
std::unordered_map<DataSliceKey, std::shared_ptr<DataSlice>> _dataSlices;

View File

@@ -33,6 +33,7 @@ in vec2 coords;
flat in float ge_screenSpaceDepth;
flat in vec4 ge_positionViewSpace;
in float ta;
// in vec4 ge_gPosition;
uniform vec4 color;
uniform float opacity;
@@ -44,6 +45,9 @@ uniform vec4 cmapNaNColor;
uniform bool colormapEnabled;
uniform sampler1D colormapTexture;
// uniform int velNaNMode;
// uniform vec4 velNaNColor;
vec4 attributeScalarToRgb(float attributeData) {
float t = (attributeData - colormapMin) / (colormapMax - colormapMin);
@@ -60,7 +64,7 @@ Fragment getFragment() {
discard;
}
// Don't show points with no value for that attribute, if CmapNaNMode is Hidden
// Don't show points with no value for that attribute, if NaNRenderMode is Hidden
if (colormapEnabled && isnan(ge_colormapAttributeScalar) && cmapNaNMode == CMAPNANMODE_HIDDEN) {
discard;
}
@@ -82,6 +86,11 @@ Fragment getFragment() {
vec4 colorFromColormap = attributeScalarToRgb(ge_colormapAttributeScalar);
outputColor = vec4(colorFromColormap.rgb, colorFromColormap.a * color.a * opacity);
}
// // TODO: Remove, Just referencing so it doesn't crash
// if (velNaNMode == 0) {
// velNaNColor = vec4(1.0, 1.0, 1.0);
// }
}
Fragment frag;

View File

@@ -26,12 +26,17 @@
#include "PowerScaling/powerScalingMath.hglsl"
// const float EPS = 1e-5;
layout(points) in;
layout(triangle_strip, max_vertices = 4) out;
in float vs_colormapAttributeScalar[];
flat in float vs_linearSizeAttributeScalar[];
// in vec4 vs_gPosition[];
// out vec4 ge_gPosition;
flat out float ge_screenSpaceDepth;
out float ta;
out vec4 ge_positionViewSpace;
@@ -96,6 +101,15 @@ void main() {
ta = 1.0;
// // Discard geometry if star has no position (but wasn't a nullArray).
// // Or if observed distance is above threshold set by cutOffThreshold.
// // By discarding in gs instead of fs we save computations for when nothing is visible.
// vec4 position = gl_in[0].gl_Position;
// if (length(position) < EPS) {
// return;
// }
vec3 pos = gl_in[0].gl_Position.xyz;
dvec4 modelPos = modelMatrix * dvec4(pos, 1.0);
@@ -104,7 +118,7 @@ void main() {
if (linearSizeEnabled) {
float interpolatedSizeAtt = 1.0;
// TODO: colormapAttributeScalar should be linearSizeAttributeScalar???
// TODO: "colormapAttributeScalar" should be "linearSizeAttributeScalar"???
float colormapAttributeScalar = vs_linearSizeAttributeScalar[0];
if (colormapAttributeScalar < linearSizeMin) {
interpolatedSizeAtt = 0.0;

View File

@@ -26,16 +26,42 @@
#include "PowerScaling/powerScaling_vs.hglsl"
const float Parsec = 3.0856776e16;
layout(location = 0) in vec3 in_position;
in float in_colormapAttributeScalar;
in float in_linearSizeAttributeScalar;
in vec3 in_velocity;
// out vec4 vs_gPosition;
out float vs_colormapAttributeScalar;
flat out float vs_linearSizeAttributeScalar;
uniform bool motionEnabled;
uniform float theTime;
void main() {
vs_colormapAttributeScalar = in_colormapAttributeScalar;
vs_linearSizeAttributeScalar = in_linearSizeAttributeScalar;
// Don't show points with no value for velocity
// if (motionEnabled && (isnan(in_velocity[0]) || isnan(in_velocity[1]) || isnan(in_velocity[2]))) {
// vs_gPosition = vec4(0.0);
// gl_Position = vec4(0.0);
// return;
// }
gl_Position = vec4(in_position, 1.0);
vec4 objectPosition = vec4(in_position, 1.0);
// Add velocity if applicable
if (motionEnabled) {
// TODO: How to handle NaN velocity values???
if (!isnan(in_velocity[0]) || !isnan(in_velocity[1]) || !isnan(in_velocity[2])) {
objectPosition.xyz += 10*theTime/Parsec * in_velocity;
}
// objectPosition.xyz += theTime * vec3(500000.0, 500000.0, 500000.0);
}
gl_Position = objectPosition;
}

View File

@@ -80,12 +80,21 @@ const std::unordered_map<std::string, MessageType> _messageTypeFromSIMPType{
{ "FPSI", MessageType::FixedSize },
{ "LPSI", MessageType::LinearSize },
{ "TOVI", MessageType::Visibility },
{ "DISC", MessageType::Disconnection },
};
const std::unordered_map<std::string, CmapNaNMode> _cmapNaNModeFromString{
{"Hide", CmapNaNMode::Hide},
{"Color", CmapNaNMode::Color}
const std::unordered_map<std::string, NaNRenderMode> _naNRenderModeFromString{
{ "Hide", NaNRenderMode::Hide},
{ "Color", NaNRenderMode::Color },
};
const std::unordered_map<std::string, LengthUnit> _lengthUnitFromString {
{ "m", LengthUnit::m },
{ "km", LengthUnit::km },
{ "AU", LengthUnit::AU },
{ "lyr", LengthUnit::lyr },
{ "pc", LengthUnit::pc },
{ "kpc", LengthUnit::kpc },
{ "Mpc", LengthUnit::Mpc },
};
glm::vec4 readSingleColor(const std::vector<char>& message, size_t& offset) {
@@ -137,6 +146,10 @@ SimpError::SimpError(const tools::ErrorCode _errorCode, const std::string& msg)
: errorCode{errorCode}, ghoul::RuntimeError(fmt::format("{}: Error Code: {} - {}", "SIMP error", static_cast<uint32_t>(_errorCode), msg), "Software Integration Messaging Protocol error")
{}
SimpError::SimpError(const std::string& msg)
: errorCode{tools::ErrorCode::Generic}, ghoul::RuntimeError(fmt::format("{}: Error Code: {} - {}", "SIMP error", static_cast<uint32_t>(errorCode), msg), "Software Integration Messaging Protocol error")
{}
MessageType getMessageType(const std::string& type) {
if (_messageTypeFromSIMPType.count(type) == 0) return MessageType::Unknown;
return _messageTypeFromSIMPType.at(type);
@@ -154,9 +167,14 @@ std::string getSIMPType(const MessageType& type) {
return it->first;
}
CmapNaNMode getCmapNaNMode(const std::string& type) {
if (_cmapNaNModeFromString.count(type) == 0) return CmapNaNMode::Unknown;
return _cmapNaNModeFromString.at(type);
NaNRenderMode getNaNRenderMode(const std::string& type) {
if (_naNRenderModeFromString.count(type) == 0) return NaNRenderMode::Unknown;
return _naNRenderModeFromString.at(type);
}
LengthUnit getLengthUnit(const std::string& type) {
if (_lengthUnitFromString.count(type) == 0) return LengthUnit::Unknown;
return _lengthUnitFromString.at(type);
}
std::string formatLengthOfSubject(size_t lengthOfSubject) {

View File

@@ -33,6 +33,7 @@ namespace storage {
enum class Key : uint8_t {
DataPoints = 0,
VelocityData,
Colormap,
ColormapAttrData,
LinearSizeAttrData,
@@ -63,6 +64,7 @@ const char SEP = ';';
enum class MessageType : uint32_t {
Connection = 0,
PointData,
VelocityData,
RemoveSceneGraphNode,
Color,
Colormap,
@@ -71,16 +73,27 @@ enum class MessageType : uint32_t {
FixedSize,
LinearSize,
Visibility,
Disconnection,
InternalDisconnection,
Unknown
};
enum class CmapNaNMode : uint32_t {
enum class NaNRenderMode : uint32_t {
Hide = 0,
Color,
Unknown
};
enum class LengthUnit : uint32_t {
m = 0,
km,
AU,
lyr,
pc,
kpc,
Mpc,
Unknown
};
namespace tools {
enum class ErrorCode : uint32_t {
@@ -95,6 +108,7 @@ enum class ErrorCode : uint32_t {
class SimpError : public ghoul::RuntimeError {
public:
tools::ErrorCode errorCode;
explicit SimpError(const std::string& msg);
explicit SimpError(const tools::ErrorCode _errorCode, const std::string& msg);
};
@@ -102,7 +116,9 @@ MessageType getMessageType(const std::string& type);
std::string getSIMPType(const MessageType& type);
CmapNaNMode getCmapNaNMode(const std::string& type);
NaNRenderMode getNaNRenderMode(const std::string& type);
LengthUnit getLengthUnit(const std::string& type);
std::string formatLengthOfSubject(size_t lengthOfSubject);