merge with master

This commit is contained in:
Jonathan Bosson
2017-04-24 08:53:38 -06:00
84 changed files with 1944 additions and 636 deletions

View File

@@ -74,6 +74,7 @@ target_compile_definitions(${APPLICATION_NAME} PUBLIC ${SGCT_OPENVR_DEFINITIONS}
if (MSVC)
target_link_libraries(${APPLICATION_NAME} Dbghelp.lib)
set_target_properties(${APPLICATION_NAME} PROPERTIES LINK_FLAGS
"/NODEFAULTLIB:LIBCMTD.lib /NODEFAULTLIB:LIBCMT.lib"
)

View File

@@ -32,6 +32,22 @@
#include <sgct.h>
#ifdef WIN32
#include <openspace/openspace.h>
#include <ghoul/filesystem/filesystem.h>
#include <ghoul/misc/stacktrace.h>
#include <fmt/format.h>
#include <Windows.h>
#include <dbghelp.h>
#include <shellapi.h>
#include <shlobj.h>
#endif // WIN32
#ifdef OPENVR_SUPPORT
#include <SGCTOpenVR.h>
#endif // OPENVR_SUPPORT
@@ -43,6 +59,73 @@ namespace {
const char* _loggerCat = "main";
sgct::Engine* SgctEngine;
#ifdef WIN32
LONG WINAPI generateMiniDump(EXCEPTION_POINTERS* exceptionPointers) {
SYSTEMTIME stLocalTime;
GetLocalTime(&stLocalTime);
LFATAL("Printing Stack Trace that lead to the crash:");
std::vector<std::string> stackTrace = ghoul::stackTrace();
for (const std::string& s : stackTrace) {
LINFO(s);
}
std::string dumpFile = fmt::format(
"OpenSpace_{}_{}_{}-{}-{}-{}-{}-{}-{}--{}--{}.dmp",
openspace::OPENSPACE_VERSION_MAJOR,
openspace::OPENSPACE_VERSION_MINOR,
openspace::OPENSPACE_VERSION_PATCH,
stLocalTime.wYear,
stLocalTime.wMonth,
stLocalTime.wDay,
stLocalTime.wHour,
stLocalTime.wMinute,
stLocalTime.wSecond,
GetCurrentProcessId(),
GetCurrentThreadId()
);
LINFO("Creating dump file: " << dumpFile);
HANDLE hDumpFile = CreateFile(
dumpFile.c_str(),
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_WRITE | FILE_SHARE_READ,
0,
CREATE_ALWAYS,
0,
0
);
MINIDUMP_EXCEPTION_INFORMATION exceptionParameter;
exceptionParameter.ThreadId = GetCurrentThreadId();
exceptionParameter.ExceptionPointers = exceptionPointers;
exceptionParameter.ClientPointers = TRUE;
BOOL success = MiniDumpWriteDump(
GetCurrentProcess(),
GetCurrentProcessId(),
hDumpFile,
MiniDumpWithDataSegs,
&exceptionParameter,
nullptr,
nullptr
);
if (success) {
LINFO("Created successfully");
}
else {
LERROR("Dumpfile created unsuccessfully");
}
return EXCEPTION_EXECUTE_HANDLER;
}
#endif // WIN32
#ifdef OPENVR_SUPPORT
sgct::SGCTWindow* FirstOpenVRWindow = nullptr;
@@ -175,13 +258,11 @@ void mainRenderFunc() {
}
#endif
if (SgctEngine->isMaster()) {
OsEng.render(viewMatrix, projectionMatrix);
}
else {
glm::mat4 sceneMatrix = SgctEngine->getModelMatrix();
OsEng.render(viewMatrix * sceneMatrix, projectionMatrix);
}
OsEng.render(
SgctEngine->getModelMatrix(),
viewMatrix,
projectionMatrix
);
LTRACE("main::mainRenderFunc(end)");
}
@@ -397,6 +478,10 @@ int main_main(int argc, char** argv) {
} // namespace
int main(int argc, char** argv) {
#ifdef WIN32
SetUnhandledExceptionFilter(generateMiniDump);
#endif // WIN32
// If we are working as a developer, we don't want to catch the exceptions in order to
// find the locations where the exceptions are raised.
// If we are not in developer mode, we want to catch and at least log the error before

View File

@@ -49,6 +49,7 @@ return {
MieColor = {1.0, 1.0, 1.0}
}
},
Tag = {"planet_solarSystem", "planet_terrestrial"},
Transform = {
Rotation = {
Type = "SpiceRotation",
@@ -78,9 +79,10 @@ return {
-- EndTime = "2017 JAN 01 12:00:00.000",
-- SampleInterval = 3600
Period = 365.242,
Resolution = 1000
Resolution = 1000,
Tag = {"planetTrail_solarSystem", "planetTrail_terrestrial"}
},
GuiName = "/Solar/EarthTrail"
GuiName = "/Solar/EarthTrail",
},
--[[
{

View File

@@ -35,6 +35,7 @@ return {
MieColor = {1.0, 1.0, 1.0}
}
},
Tag = "planet_solarSystem",
Transform = {
Translation = {
Type = "StaticTranslation",
@@ -64,7 +65,8 @@ return {
},
Color = { 0.8, 0.7, 0.7 },
Period = 4330.595,
Resolution = 1000
}
Resolution = 1000,
},
Tag = "planetTrail_solarSystem"
}
}

View File

@@ -76,10 +76,6 @@ return {
FilePath = "map_service_configs/ESRI/ESRI_Imagery_World_2D.wms",
Name = "ESRI",
},
{
Name = "ESRI Imagery World 2D",
FilePath = "map_service_configs/ESRI/ESRI_Imagery_World_2D.wms",
},
{
Name = "ESRI Imagery World",
FilePath = "map_service_configs/ESRI/ESRI_Imagery_World_2D.wms"
@@ -94,6 +90,11 @@ return {
Name = "Temporal_GHRSST_L4_MUR_Sea_Surface_Temperature",
FilePath = "map_service_configs/GIBS/Temporal_GHRSST_L4_MUR_Sea_Surface_Temperature.xml",
},
{
Type = "Temporal",
Name = "Temporal_AMSR2_GCOM_W1_Sea_Ice_Concentration",
FilePath = "map_service_configs/GIBS/Temporal_AMSR2_GCOM_W1_Sea_Ice_Concentration.xml",
},
-- {
-- Type = "SingleImage",
-- Name = "Debug Tiles",
@@ -120,7 +121,7 @@ return {
{
Type = "Temporal",
Name = "Temporal Earth at Night",
FilePath = "map_service_configs/GIBS/Temporal_VIIRS_CityLights.xml"
FilePath = "map_service_configs/GIBS/Temporal_VIIRS_SNPP_DayNightBand_ENCC.xml"
}
},
WaterMasks = {

View File

@@ -0,0 +1,28 @@
<OpenSpaceTemporalGDALDataset>
<OpenSpaceTimeStart>2012-05-08</OpenSpaceTimeStart>
<OpenSpaceTimeEnd></OpenSpaceTimeEnd>
<OpenSpaceTimeResolution>1d</OpenSpaceTimeResolution>
<OpenSpaceTimeIdFormat>YYYY-MM-DD</OpenSpaceTimeIdFormat>
<GDAL_WMS>
<Service name="TMS">
<ServerUrl>https://gibs.earthdata.nasa.gov/wmts/epsg4326/best/AMSR2_Sea_Ice_Concentration_12km/default/${OpenSpaceTimeId}/2km/${z}/${y}/${x}.png</ServerUrl>
</Service>
<DataWindow>
<UpperLeftX>-180.0</UpperLeftX>
<UpperLeftY>90</UpperLeftY>
<LowerRightX>396.0</LowerRightX>
<LowerRightY>-198</LowerRightY>
<TileLevel>8</TileLevel>
<TileCountX>2</TileCountX>
<TileCountY>1</TileCountY>
<YOrigin>top</YOrigin>
</DataWindow>
<Projection>EPSG:4326</Projection>
<BlockSizeX>512</BlockSizeX>
<BlockSizeY>512</BlockSizeY>
<BandsCount>3</BandsCount>
<UnsafeSSL>true</UnsafeSSL>
<ZeroBlockHttpCodes>400</ZeroBlockHttpCodes>
<ZeroBlockOnServerException>true</ZeroBlockOnServerException>
</GDAL_WMS>
</OpenSpaceTemporalGDALDataset>

View File

@@ -62,4 +62,10 @@
</DataWindow>
<BlockSizeX>512</BlockSizeX>
<BlockSizeY>512</BlockSizeY>
<Cache>
<Path>./GDAL_Cache/OnMoonColor</Path>
<Depth>4</Depth>
<Extension>.png</Extension>
</Cache>
</GDAL_WMS>

View File

@@ -16,4 +16,9 @@
<TileCountY>1</TileCountY>
<YOrigin>top</YOrigin>
</DataWindow>
<Cache>
<Path>./GDAL_Cache/OnMoonHeight</Path>
<Depth>4</Depth>
<Extension>.png</Extension>
</Cache>
</GDAL_WMS>

View File

@@ -35,12 +35,17 @@ return {
MieColor = {1.0, 1.0, 1.0}
}
},
Tag = {"planet_solarSystem", "planet_terrestrial"},
Transform = {
Rotation = {
Type = "SpiceRotation",
SourceFrame = "IAU_MARS",
DestinationFrame = "GALACTIC",
},
Scale = {
Type = "StaticScale",
Scale = 1,
},
}
},
-- MarsTrail module
@@ -56,7 +61,8 @@ return {
},
Color = { 0.814, 0.305, 0.220 },
Period = 686.973,
Resolution = 1000
Resolution = 1000,
Tag = {"planetTrail_solarSystem", "planetTrail_terrestrial"}
}
}
}

View File

@@ -35,6 +35,7 @@ return {
MieColor = {1.0, 1.0, 1.0}
}
},
Tag = {"planet_solarSystem", "planet_terrestrial"},
Transform = {
Rotation = {
Type = "SpiceRotation",
@@ -60,7 +61,8 @@ return {
},
Color = {0.6, 0.5, 0.5 },
Period = 87.968,
Resolution = 100
Resolution = 100,
Tag = {"planetTrail_solarSystem", "planetTrail_terrestrial"}
}
}
}

View File

@@ -29,14 +29,19 @@ return {
Textures = {
Type = "simple",
Color = "textures/neptune.jpg",
},
}
},
Translation = {
Tag = "planet_solarSystem",
Transform = {
Rotation = {
Type = "SpiceRotation",
SourceFrame = "IAU_NEPTUNE",
DestinationFrame = "GALACTIC"
},
Scale = {
Type = "StaticScale",
Scale = 1,
},
}
},
-- NeptuneTrail module
@@ -52,7 +57,8 @@ return {
},
Color = {0.2, 0.5, 1.0 },
Period = 60200,
Resolution = 1000
},
Resolution = 1000,
Tag = "planetTrail_solarSystem"
}
}
}

View File

@@ -36,6 +36,7 @@ return {
MieColor = {1.0, 1.0, 1.0}
}
},
Tag = "planet_solarSystem",
Transform = {
Rotation = {
Type = "SpiceRotation",
@@ -73,7 +74,8 @@ return {
},
Color = {0.85,0.75,0.51 },
Period = 10746.94,
Resolution = 1000
Resolution = 1000,
Tag = "planetTrail_solarSystem"
},
}
}

View File

@@ -36,12 +36,17 @@ return {
MieColor = {1.0, 1.0, 1.0}
}
},
Tag = "planet_solarSystem",
Transform = {
Rotation = {
Type = "SpiceRotation",
SourceFrame = "IAU_URANUS",
DestinationFrame = "ECLIPJ2000",
}
},
Scale = {
Type = "StaticScale",
Scale = 1,
},
},
},
@@ -58,7 +63,8 @@ return {
},
Color = {0.60, 0.95, 1.00 },
Period = 30588.740,
Resolution = 1000
},
Resolution = 1000,
Tag = "planetTrail_solarSystem"
}
}
}

View File

@@ -36,10 +36,17 @@ return {
MieColor = {1.0, 1.0, 1.0}
}
},
Rotation = {
Type = "SpiceRotation",
Frame = "IAU_VENUS",
Reference = "GALACTIC"
Tag = {"planet_solarSystem", "planet_terrestrial"},
Transform = {
Rotation = {
Type = "SpiceRotation",
SourceFrame = "IAU_VENUS",
DestinationFrame = "GALACTIC"
},
Scale = {
Type = "StaticScale",
Scale = 1,
},
},
},
@@ -56,7 +63,8 @@ return {
},
Color = { 1.0, 0.5, 0.2 },
Period = 224.695,
Resolution = 1000
Resolution = 1000,
Tag = {"planetTrail_solarSystem", "planetTrail_terrestrial"}
}
}
}

View File

@@ -216,6 +216,19 @@ struct StringListVerifier : public TableVerifier {
std::string type() const override;
};
/**
* A Verifier that checks whether all values contained in a Table are of type \c int.
*/
struct IntListVerifier : public TableVerifier {
/**
* Constructor for a IntListVerifier.
* \param elementDocumentation The documentation for each string in the list
*/
IntListVerifier(std::string elementDocumentation = "");
std::string type() const override;
};
//----------------------------------------------------------------------------------------
// Vector verifiers
//----------------------------------------------------------------------------------------

View File

@@ -104,6 +104,8 @@ public:
/// The key that stores whether the master node should perform rendering just function
/// as a pure manager
static const std::string KeyDisableMasterRendering;
/// The key that stores whether the master node should apply the scene transformation
static const std::string KeyDisableSceneOnMaster;
/// The key that sets the request URL that is used to request additional data to be
/// downloaded
static const std::string KeyDownloadRequestURL;
@@ -124,7 +126,22 @@ public:
static const std::string PartHttpProxyUser;
/// The key that stores the password to use for authentication to access the http proxy
static const std::string PartHttpProxyPassword;
/// The key that stores the dictionary containing information about debug contexts
static const std::string KeyOpenGLDebugContext;
/// The part of the key storing whether an OpenGL Debug context should be created
static const std::string PartActivate;
/// The part of the key storing whether the debug callbacks are performed synchronous
static const std::string PartSynchronous;
/// The part of the key storing a list of identifiers that should be filtered out
static const std::string PartFilterIdentifier;
/// The part of the key that stores the source of the ignored identifier
static const std::string PartFilterIdentifierSource;
/// The part of the key that stores the type of the ignored identifier
static const std::string PartFilterIdentifierType;
/// The part of the key that stores the identifier of the ignored identifier
static const std::string PartFilterIdentifierIdentifier;
/// The part of the key storing a list of severities that should be filtered out
static const std::string PartFilterSeverity;
/**
* Iteratively walks the directory structure starting with \p filename to find the

View File

@@ -88,7 +88,8 @@ public:
void deinitialize();
void preSynchronization();
void postSynchronizationPreDraw();
void render(const glm::mat4& viewMatrix, const glm::mat4& projectionMatrix);
void render(const glm::mat4& sceneMatrix, const glm::mat4& viewMatrix,
const glm::mat4& projectionMatrix);
void postDraw();
void keyboardCallback(Key key, KeyModifier mod, KeyAction action);
void charCallback(unsigned int codepoint, KeyModifier mod);

View File

@@ -65,6 +65,7 @@ public:
// Interaction mode setters
void setCameraStateFromDictionary(const ghoul::Dictionary& cameraDict);
void setInteractionMode(const std::string& interactionModeKey);
InteractionMode* interactionMode();
void goToChunk(int x, int y, int level);
void goToGeo(double latitude, double longitude);
@@ -72,7 +73,9 @@ public:
void resetKeyBindings();
void addKeyframe(const datamessagestructures::CameraKeyframe &kf);
void removeKeyframesAfter(double timestamp);
void clearKeyframes();
const std::vector<datamessagestructures::CameraKeyframe>& keyframes() const;
void bindKeyLocal(
Key key,
@@ -96,6 +99,8 @@ public:
// Accessors
ghoul::Dictionary getCameraStateDictionary();
SceneGraphNode* const focusNode() const;
glm::dvec3 focusNodeToCameraVector() const;
glm::quat focusNodeToCameraRotation() const;
Camera* const camera() const;
std::shared_ptr<InteractionMode> interactionmode();
const InputState& inputState() const;

View File

@@ -82,9 +82,12 @@ namespace interaction {
// Mutators
void addKeyframe(const datamessagestructures::CameraKeyframe &kf);
void removeKeyframesAfter(double timestamp);
void clearKeyframes();
void clearOldKeyframes();
static bool compareKeyframeTimes(const datamessagestructures::CameraKeyframe& a, const datamessagestructures::CameraKeyframe& b);
// Accessors
const std::list<std::pair<Key, KeyModifier> >& getPressedKeys() const;
const std::list<MouseButton>& getPressedMouseButtons() const;
@@ -119,6 +122,7 @@ public:
// Accessors
SceneGraphNode* focusNode();
Interpolator<double>& rotateToFocusNodeInterpolator();
virtual bool followingNodeRotation() const = 0;
virtual void updateMouseStatesFromInput(const InputState& inputState, double deltaTime) = 0;
virtual void updateCameraStateFromMouseStates(Camera& camera, double deltaTime) = 0;
@@ -195,6 +199,7 @@ public:
virtual void updateMouseStatesFromInput(const InputState& inputState, double deltaTime);
virtual void updateCameraStateFromMouseStates(Camera& camera, double deltaTime);
bool followingNodeRotation() const override;
private:
std::vector<datamessagestructures::CameraKeyframe> _keyframes;
@@ -245,6 +250,7 @@ public:
virtual void updateMouseStatesFromInput(const InputState& inputState, double deltaTime);
virtual void updateCameraStateFromMouseStates(Camera& camera, double deltaTime);
bool followingNodeRotation() const override;
protected:
//void updateCameraStateFromMouseStates(Camera& camera, double deltaTime);
@@ -260,6 +266,7 @@ public:
virtual void setFocusNode(SceneGraphNode* focusNode);
//virtual void update(Camera& camera, const InputState& inputState, double deltaTime);
virtual void updateCameraStateFromMouseStates(Camera& camera, double deltaTime);
bool followingNodeRotation() const override;
#ifdef OPENSPACE_MODULE_GLOBEBROWSING_ENABLED
void goToChunk(Camera& camera, globebrowsing::TileIndex ti, glm::vec2 uv,
bool resetCameraDirection);

View File

@@ -53,7 +53,7 @@ private:
void addToCommand(std::string c);
properties::BoolProperty _isVisible;
bool _remoteScripting;
properties::BoolProperty _remoteScripting;
size_t _inputPosition;
std::vector<std::string> _commandsHistory;

View File

@@ -51,16 +51,28 @@ struct CameraKeyframe {
glm::dvec3 _position;
glm::dquat _rotation;
bool _followNodeRotation;
std::string _focusNode;
double _timestamp;
void serialize(std::vector<char> &buffer){
//add position
// Add position
buffer.insert(buffer.end(), reinterpret_cast<char*>(&_position), reinterpret_cast<char*>(&_position) + sizeof(_position));
//add orientation
// Add orientation
buffer.insert(buffer.end(), reinterpret_cast<char*>(&_rotation), reinterpret_cast<char*>(&_rotation) + sizeof(_rotation));
//add timestamp
// Follow focus node rotation?
buffer.insert(buffer.end(), reinterpret_cast<char*>(&_followNodeRotation), reinterpret_cast<char*>(&_followNodeRotation) + sizeof(_followNodeRotation));
int nodeNameLength = _focusNode.size();
// Add focus node
buffer.insert(buffer.end(), reinterpret_cast<char*>(&nodeNameLength), reinterpret_cast<char*>(&nodeNameLength) + sizeof(nodeNameLength));
buffer.insert(buffer.end(), _focusNode.data(), _focusNode.data() + nodeNameLength);
// Add timestamp
buffer.insert(buffer.end(), reinterpret_cast<char*>(&_timestamp), reinterpret_cast<char*>(&_timestamp) + sizeof(_timestamp));
};
@@ -68,17 +80,31 @@ struct CameraKeyframe {
int offset = 0;
int size = 0;
//position
// Position
size = sizeof(_position);
memcpy(&_position, buffer.data() + offset, size);
offset += size;
//orientation
// Orientation
size = sizeof(_rotation);
memcpy(&_rotation, buffer.data() + offset, size);
offset += size;
// Follow focus node rotation?
size = sizeof(_followNodeRotation);
memcpy(&_followNodeRotation, buffer.data() + offset, size);
offset += size;
// Focus node
int nodeNameLength;
size = sizeof(int);
memcpy(&nodeNameLength, buffer.data() + offset, size);
offset += size;
size = nodeNameLength;
_focusNode = std::string(buffer.data() + offset, buffer.data() + offset + size);
offset += size;
//timestamp
// Timestamp
size = sizeof(_timestamp);
memcpy(&_timestamp, buffer.data() + offset, size);
};
@@ -97,19 +123,19 @@ struct TimeKeyframe {
double _timestamp;
void serialize(std::vector<char> &buffer){
//add current time
// Add current time
buffer.insert(buffer.end(), reinterpret_cast<char*>(&_time), reinterpret_cast<char*>(&_time) + sizeof(_time));
//add delta time
// Add delta time
buffer.insert(buffer.end(), reinterpret_cast<char*>(&_dt), reinterpret_cast<char*>(&_dt) + sizeof(_dt));
//add wether time is paused or not
// Add whether time is paused or not
buffer.insert(buffer.end(), reinterpret_cast<char*>(&_paused), reinterpret_cast<char*>(&_paused) + sizeof(_paused));
//add wether a time jump is necessary (recompute paths etc)
// Add whether a time jump is necessary (recompute paths etc)
buffer.insert(buffer.end(), reinterpret_cast<char*>(&_requiresTimeJump), reinterpret_cast<char*>(&_requiresTimeJump) + sizeof(_requiresTimeJump));
//add timestamp
// Add timestamp
buffer.insert(buffer.end(), reinterpret_cast<char*>(&_timestamp), reinterpret_cast<char*>(&_timestamp) + sizeof(_timestamp));
};
@@ -117,27 +143,27 @@ struct TimeKeyframe {
int offset = 0;
int size = 0;
//current time
// Current time
size = sizeof(_time);
memcpy(&_time, buffer.data() + offset, size);
offset += size;
//delta time
// Delta time
size = sizeof(_dt);
memcpy(&_dt, buffer.data() + offset, size);
offset += size;
//is time paused?
// Is time paused?
size = sizeof(_paused);
memcpy(&_paused, buffer.data() + offset, size);
offset += sizeof(_paused);
//is a time jump required?
// Is a time jump required?
size = sizeof(_requiresTimeJump);
memcpy(&_requiresTimeJump, buffer.data() + offset, size);
offset += size;
// timestamp
// Timestamp
size = sizeof(_timestamp);
memcpy(&_timestamp, buffer.data() + offset, size);
offset += size;

View File

@@ -27,6 +27,9 @@
//openspace includes
#include <openspace/network/messagestructures.h>
#include <openspace/properties/propertyowner.h>
#include <openspace/properties/stringproperty.h>
#include <openspace/properties/numericalproperty.h>
//glm includes
#include <glm/gtx/quaternion.hpp>
@@ -57,7 +60,7 @@ struct addrinfo;
namespace openspace {
class ParallelConnection {
class ParallelConnection : public properties::PropertyOwner {
public:
enum class Status : uint32_t {
Disconnected = 0,
@@ -99,17 +102,21 @@ class ParallelConnection {
ParallelConnection();
~ParallelConnection();
void clientConnect();
void setPort(const std::string &port);
void setAddress(const std::string &address);
void setName(const std::string& name);
void setPort(std::string port);
void setAddress(std::string address);
void setName(std::string name);
bool isHost();
const std::string& hostName();
void requestHostship(const std::string &password);
void requestHostship();
void resignHostship();
void setPassword(const std::string &password);
void setPassword(std::string password);
void setHostPassword(std::string hostPassword);
void signalDisconnect();
void preSynchronization();
void sendScript(const std::string& script);
void sendScript(std::string script);
void resetTimeOffset();
double latencyStandardDeviation() const;
double timeTolerance() const;
/**
* Returns the Lua library that contains all Lua functions available to affect the
@@ -145,7 +152,6 @@ private:
void connectionStatusMessageReceived(const std::vector<char>& messageContent);
void nConnectionsMessageReceived(const std::vector<char>& messageContent);
void broadcast();
void sendCameraKeyframe();
void sendTimeKeyframe();
@@ -158,10 +164,18 @@ private:
double calculateBufferedKeyframeTime(double originalTime);
uint32_t _passCode;
std::string _port;
std::string _address;
std::string _name;
properties::StringProperty _password;
properties::StringProperty _hostPassword;
properties::StringProperty _port;
properties::StringProperty _address;
properties::StringProperty _name;
properties::FloatProperty _bufferTime;
properties::FloatProperty _timeKeyframeInterval;
properties::FloatProperty _cameraKeyframeInterval;
properties::FloatProperty _timeTolerance;
double _lastTimeKeyframeTimestamp;
double _lastCameraKeyframeTimestamp;
_SOCKET _clientSocket;
@@ -191,7 +205,6 @@ private:
double _initialTimeDiff;
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;

View File

@@ -207,6 +207,20 @@ public:
/// \see PropertyOwner::removePropertySubOwner(PropertyOwner*)
void removePropertySubOwner(PropertyOwner& owner);
/**
* Returns a list of all tags that have been assigned to the Property. Useful for
* trying to find a match for a desired batch operation on Properties.
* \return Pointer to vector of string tags that were assigned to the Property
*/
std::vector<std::string> tags() const;
/**
* Adds a tag to the Property's list of assigned tags. Tags are useful for creating
* groups of Properties that can be used in batch operations.
* \param tag The string that is to be assigned to the Property
*/
void addTag(std::string tag);
private:
/// The name of this PropertyOwner
std::string _name;
@@ -218,6 +232,8 @@ private:
std::vector<PropertyOwner*> _subOwners;
/// The associations between group identifiers of Property's and human-readable names
std::map<std::string, std::string> _groupNames;
/// Collection of string tag(s) assigned to this property
std::vector<std::string> _tags;
};
} // namespace properties

View File

@@ -98,7 +98,8 @@ public:
void updateFade();
void updateRenderer();
void updateScreenSpaceRenderables();
void render(const glm::mat4& viewMatrix, const glm::mat4& projectionMatrix);
void render(const glm::mat4& sceneMatrix, const glm::mat4& viewMatrix,
const glm::mat4& projectionMatrix);
void renderScreenLog();
void renderShutdownInformation(float timer, float fullTime);
@@ -211,6 +212,7 @@ private:
properties::BoolProperty _applyWarping;
properties::BoolProperty _showFrameNumber;
properties::BoolProperty _disableMasterRendering;
properties::BoolProperty _disableSceneOnMaster;
float _globalBlackOutFactor;
float _fadeDuration;

View File

@@ -61,6 +61,7 @@ public:
static const std::string KeyName;
static const std::string KeyParentName;
static const std::string KeyDependencies;
static const std::string KeyTag;
SceneGraphNode();
~SceneGraphNode();
@@ -97,6 +98,8 @@ public:
glm::dvec3 worldPosition() const;
const glm::dmat3& worldRotationMatrix() const;
glm::dmat4 modelTransform() const;
glm::dmat4 inverseModelTransform() const;
double worldScale() const;
SceneGraphNode* parent() const;
@@ -140,6 +143,9 @@ private:
glm::dvec3 _worldPositionCached;
glm::dmat3 _worldRotationCached;
double _worldScaleCached;
glm::dmat4 _modelTransformCached;
glm::dmat4 _inverseModelTransformCached;
};
} // namespace openspace

View File

@@ -28,10 +28,10 @@
namespace openspace {
namespace distanceconstants {
const float EarthRadius = 6371;
const float LightYear = 9.4607304725808E15;
const float AstronomicalUnit = 1.495978707E11;
const float Parsec = 3.0856776E16;
const float EarthRadius = 6371;
const float LightYear = 9.4607304725808E15;
const float AstronomicalUnit = 1.495978707E11;
const float Parsec = 3.0856776E16;
}
}

View File

@@ -25,6 +25,7 @@
#ifndef __OPENSPACE_CORE___TIMEMANAGER___H__
#define __OPENSPACE_CORE___TIMEMANAGER___H__
#include <vector>
#include <deque>
#include <openspace/network/messagestructures.h>
@@ -35,7 +36,9 @@ public:
void preSynchronization(double dt);
void addKeyframe(const datamessagestructures::TimeKeyframe& kf);
void removeKeyframesBefore(double timestamp);
void removeKeyframesAfter(double timestamp);
void clearKeyframes();
const std::deque<datamessagestructures::TimeKeyframe>& keyframes() const;
private:
void consumeKeyframes(double dt);
std::deque<datamessagestructures::TimeKeyframe> _keyframes;

View File

@@ -33,8 +33,6 @@
#include <ghoul/filesystem/filesystem>
namespace {
const std::string _loggerCat = "ScreenSpaceImage";
const char* KeyName = "Name";
const char* KeyTexturePath = "TexturePath";
const char* KeyUrl = "URL";
@@ -46,6 +44,7 @@ ScreenSpaceImage::ScreenSpaceImage(const ghoul::Dictionary& dictionary)
: ScreenSpaceRenderable(dictionary)
, _texturePath("texturePath", "Texture path", "")
, _downloadImage(false)
, _textureIsDirty(false)
{
std::string name;
if (dictionary.getValue(KeyName, name)) {
@@ -61,7 +60,7 @@ ScreenSpaceImage::ScreenSpaceImage(const ghoul::Dictionary& dictionary)
std::string texturePath;
if (dictionary.getValue(KeyTexturePath, texturePath)) {
_texturePath = texturePath;
_texturePath.onChange([this](){ loadTexture(); });
_texturePath.onChange([this]() { _textureIsDirty = true; });
}
if (dictionary.getValue(KeyUrl, _url)) {
@@ -82,7 +81,6 @@ bool ScreenSpaceImage::initialize() {
}
bool ScreenSpaceImage::deinitialize() {
glDeleteVertexArrays(1, &_quad);
_quad = 0;
@@ -106,7 +104,7 @@ void ScreenSpaceImage::render() {
void ScreenSpaceImage::update() {
bool download = _downloadImage ? (_futureImage.valid() && DownloadManager::futureReady(_futureImage)) : true;
if (download) {
if (download && _textureIsDirty) {
loadTexture();
}
}
@@ -130,6 +128,7 @@ void ScreenSpaceImage::loadTexture() {
texture->setFilter(ghoul::opengl::Texture::FilterMode::Linear);
_texture = std::move(texture);
_textureIsDirty = false;
}
}
@@ -178,10 +177,16 @@ std::future<DownloadManager::MemoryFile> ScreenSpaceImage::downloadImageToMemory
return std::move(OsEng.downloadManager().fetchFile(
url,
[url](const DownloadManager::MemoryFile& file) {
LDEBUG("Download to memory finished for screen space image");
LDEBUGC(
"ScreenSpaceImage",
"Download to memory finished for screen space image"
);
},
[url](const std::string& err) {
LDEBUG("Download to memory failer for screen space image: " +err);
LDEBUGC(
"ScreenSpaceImage",
"Download to memory failer for screen space image: " + err
);
}
));
}

View File

@@ -51,6 +51,7 @@ protected:
std::string _url;
bool _downloadImage;
bool _textureIsDirty;
std::future<DownloadManager::MemoryFile> _futureImage;
private:
@@ -59,6 +60,8 @@ private:
std::unique_ptr<ghoul::opengl::Texture> loadFromMemory();
properties::StringProperty _texturePath;
};
} // namespace openspace

View File

@@ -22,8 +22,6 @@
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#version __CONTEXT__
uniform sampler2D texture1;
uniform float OcclusionDepth;
uniform float Alpha;

View File

@@ -121,7 +121,7 @@ RenderableFieldlines::RenderableFieldlines(const ghoul::Dictionary& dictionary)
}
// @TODO a non-magic number perhaps ---abock
setBoundingSphere(PowerScaledScalar::CreatePSS(250.f*6371000.f));
setBoundingSphere(250.f*6371000.f);
_seedPointSource.addOption(SeedPointSourceFile, "File");
_seedPointSource.addOption(SeedPointSourceTable, "Lua Table");

View File

@@ -101,6 +101,7 @@ set(HEADER_FILES
${CMAKE_CURRENT_SOURCE_DIR}/tile/loadjob/loadjob.h
${CMAKE_CURRENT_SOURCE_DIR}/tile/loadjob/tileloadjob.h
${CMAKE_CURRENT_SOURCE_DIR}/tile/tileprovider/cachingtileprovider.h
${CMAKE_CURRENT_SOURCE_DIR}/tile/tileprovider/presentationslideprovider.h
${CMAKE_CURRENT_SOURCE_DIR}/tile/tileprovider/singleimageprovider.h
${CMAKE_CURRENT_SOURCE_DIR}/tile/tileprovider/sizereferencetileprovider.h
${CMAKE_CURRENT_SOURCE_DIR}/tile/tileprovider/temporaltileprovider.h
@@ -166,6 +167,7 @@ set(SOURCE_FILES
${CMAKE_CURRENT_SOURCE_DIR}/tile/asynctiledataprovider.cpp
${CMAKE_CURRENT_SOURCE_DIR}/tile/pixelregion.cpp
${CMAKE_CURRENT_SOURCE_DIR}/tile/rawtile.cpp
${CMAKE_CURRENT_SOURCE_DIR}/tile/tile.cpp
${CMAKE_CURRENT_SOURCE_DIR}/tile/tilediskcache.cpp
${CMAKE_CURRENT_SOURCE_DIR}/tile/tileindex.cpp
@@ -174,6 +176,7 @@ set(SOURCE_FILES
${CMAKE_CURRENT_SOURCE_DIR}/tile/loadjob/diskcachedtileloadjob.cpp
${CMAKE_CURRENT_SOURCE_DIR}/tile/loadjob/tileloadjob.cpp
${CMAKE_CURRENT_SOURCE_DIR}/tile/tileprovider/cachingtileprovider.cpp
${CMAKE_CURRENT_SOURCE_DIR}/tile/tileprovider/presentationslideprovider.cpp
${CMAKE_CURRENT_SOURCE_DIR}/tile/tileprovider/singleimageprovider.cpp
${CMAKE_CURRENT_SOURCE_DIR}/tile/tileprovider/sizereferencetileprovider.cpp
${CMAKE_CURRENT_SOURCE_DIR}/tile/tileprovider/temporaltileprovider.cpp

View File

@@ -38,17 +38,17 @@ namespace cache {
*/
class MemoryAwareCacheable {
public:
/**
* \param memoryImpact is the memory impact of the object. Can for example be given
* in kilobytes.
*/
MemoryAwareCacheable(size_t memoryImpact) : _memoryImpact(memoryImpact) {};
~MemoryAwareCacheable() {};
/**
* \param memoryImpact is the memory impact of the object. Can for example be given
* in kilobytes.
*/
MemoryAwareCacheable(size_t memoryImpact) : _memoryImpact(memoryImpact) {};
~MemoryAwareCacheable() {};
size_t memoryImpact() { return _memoryImpact; };
size_t memoryImpact() { return _memoryImpact; };
protected:
size_t _memoryImpact;
size_t _memoryImpact;
};
} // namespace cache

View File

@@ -103,7 +103,7 @@ private:
static MemoryAwareTileCache* _singleton;
MemoryAwareLRUCache<ProviderTileKey, Tile, ProviderTileHasher> _tileCache;
static std::mutex _mutexLock;
static std::mutex _mutexLock;
};
} // namespace cache

View File

@@ -0,0 +1,36 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2017 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#ifndef __OPENSPACE_MODULE_GLOBEBROWSING___GDAL___H__
#define __OPENSPACE_MODULE_GLOBEBROWSING___GDAL___H__
#ifdef WIN32
#pragma warning(push, 0)
#endif // WIN32
#include <gdal_priv.h>
#ifdef WIN32
#pragma warning(pop)
#endif // WIN32

View File

@@ -37,6 +37,7 @@
#include <modules/globebrowsing/tile/tileprovider/tileprovider.h>
#include <modules/globebrowsing/tile/tileprovider/tileproviderbylevel.h>
#include <modules/globebrowsing/tile/tileprovider/tileproviderbyindex.h>
#include <modules/globebrowsing/tile/tileprovider/presentationslideprovider.h>
#include <openspace/engine/openspaceengine.h>
#include <openspace/rendering/renderable.h>
@@ -89,7 +90,7 @@ void GlobeBrowsingModule::internalInitialize() {
CpuCap.installedMainMemory() * 0.25 * 1024 * 1024); // 25% of total RAM
addPropertySubOwner(GdalWrapper::ref());
#endif // GLOBEBROWSING_USE_GDAL
});
});
OsEng.registerModuleCallback(OpenSpaceEngine::CallbackOption::Deinitialize, [&]{
cache::MemoryAwareTileCache::ref().clear();
@@ -118,7 +119,7 @@ void GlobeBrowsingModule::internalInitialize() {
// Combining Tile Providers
fTileProvider->registerClass<tileprovider::TileProviderByLevel>("ByLevel");
fTileProvider->registerClass<tileprovider::TileProviderByIndex>("ByIndex");
fTileProvider->registerClass<tileprovider::PresentationSlideProvider>("PresentationSlides");
FactoryManager::ref().addFactory(std::move(fTileProvider));
}

View File

@@ -107,18 +107,18 @@ ghoul::opengl::ProgramObject* ChunkRenderer::getActivatedProgramWithTileData(
std::to_string(debugProps.showHeightResolution));
pairs.emplace_back("showHeightIntensities",
std::to_string(debugProps.showHeightIntensities));
pairs.emplace_back("defaultHeight", std::to_string(Chunk::DEFAULT_HEIGHT));
pairs.emplace_back("defaultHeight", std::to_string(Chunk::DEFAULT_HEIGHT));
pairs.emplace_back("tilePaddingStart",
"ivec2(" +
std::to_string(RawTileDataReader::padding.start.x) + "," +
std::to_string(RawTileDataReader::padding.start.y) + ")"
);
pairs.emplace_back("tilePaddingSizeDiff",
"ivec2(" +
std::to_string(RawTileDataReader::padding.numPixels.x) + "," +
std::to_string(RawTileDataReader::padding.numPixels.y) + ")"
);
pairs.emplace_back("tilePaddingStart",
"ivec2(" +
std::to_string(RawTileDataReader::padding.start.x) + "," +
std::to_string(RawTileDataReader::padding.start.y) + ")"
);
pairs.emplace_back("tilePaddingSizeDiff",
"ivec2(" +
std::to_string(RawTileDataReader::padding.numPixels.x) + "," +
std::to_string(RawTileDataReader::padding.numPixels.y) + ")"
);
// Now the shader program can be accessed
ghoul::opengl::ProgramObject* programObject =

View File

@@ -39,23 +39,23 @@ LayerRenderSettings::LayerRenderSettings()
}
float LayerRenderSettings::performLayerSettings(float currentValue) const {
float newValue = currentValue;
float newValue = currentValue;
newValue = glm::sign(newValue) * glm::pow(glm::abs(newValue), gamma);
newValue = newValue * multiplier;
newValue = newValue * opacity;
newValue = glm::sign(newValue) * glm::pow(glm::abs(newValue), gamma);
newValue = newValue * multiplier;
newValue = newValue * opacity;
return newValue;
return newValue;
}
glm::vec4 LayerRenderSettings::performLayerSettings(glm::vec4 currentValue) const {
glm::vec4 newValue = glm::vec4(
performLayerSettings(currentValue.r),
performLayerSettings(currentValue.g),
performLayerSettings(currentValue.b),
performLayerSettings(currentValue.a));
glm::vec4 newValue = glm::vec4(
performLayerSettings(currentValue.r),
performLayerSettings(currentValue.g),
performLayerSettings(currentValue.b),
performLayerSettings(currentValue.a));
return newValue;
return newValue;
}
} // namespace globebrowsing

View File

@@ -41,7 +41,7 @@ struct LayerRenderSettings : public properties::PropertyOwner {
/// This function matches the function with the same name in the
/// shader code
float performLayerSettings(float currentValue) const;
/// This function matches the function with the same name in the
/// This function matches the function with the same name in the
/// shader code
glm::vec4 performLayerSettings(glm::vec4 currentValue) const;
};

View File

@@ -34,11 +34,11 @@ namespace openspace {
namespace globebrowsing {
struct ChunkTile {
ChunkTile() : tile(Tile::TileUnavailable) {};
ChunkTile(Tile tile, TileUvTransform uvTransform, TileDepthTransform depthTransform) :
tile(tile),
uvTransform(uvTransform),
depthTransform(depthTransform) {};
ChunkTile() : tile(Tile::TileUnavailable) {};
ChunkTile(Tile tile, TileUvTransform uvTransform, TileDepthTransform depthTransform) :
tile(tile),
uvTransform(uvTransform),
depthTransform(depthTransform) {};
Tile tile;
TileUvTransform uvTransform;

View File

@@ -31,8 +31,8 @@ namespace globebrowsing {
TileLoadJob::TileLoadJob(std::shared_ptr<RawTileDataReader> rawTileDataReader,
const TileIndex& tileIndex)
: _rawTileDataReader(rawTileDataReader)
, _chunkIndex(tileIndex) {}
: _rawTileDataReader(rawTileDataReader)
, _chunkIndex(tileIndex) {}
void TileLoadJob::execute() {
_rawTile = _rawTileDataReader->readTileData(_chunkIndex);

View File

@@ -54,13 +54,16 @@ std::ostream& operator<<(std::ostream& os, const PixelRegion& pr) {
", " << pr.numPixels.y;
}
GdalRawTileDataReader::GdalRawTileDataReader(
const std::string& filePath, const Configuration& config)
GdalRawTileDataReader::GdalRawTileDataReader(const std::string& filePath,
const Configuration& config,
const std::string& baseDirectory)
: RawTileDataReader(config)
, _dataset(nullptr)
{
_initData = { "", filePath, config.tilePixelSize, config.dataType };
_initData.initDirectory = CPLGetCurrentDir();
std::string initDir = baseDirectory.empty() ? CPLGetCurrentDir() : baseDirectory;
_initData = { initDir, filePath, config.tilePixelSize, config.dataType };
ensureInitialized();
}
@@ -303,6 +306,7 @@ GDALDataset* GdalRawTileDataReader::openGdalDataset(const std::string& filePath)
std::string correctedPath = FileSystem::ref().pathByAppendingComponent(
_initData.initDirectory, filePath
);
dataset = (GDALDataset *)GDALOpen(correctedPath.c_str(), GA_ReadOnly);
if (!dataset) {
throw ghoul::RuntimeError("Failed to load dataset:\n" + filePath);

View File

@@ -60,8 +60,10 @@ public:
*
* \param filePath, a path to a specific file GDAL can read
* \param config, Configuration used for initialization
* \param baseDirectory, the base directory to use in future loading operations
*/
GdalRawTileDataReader(const std::string& filePath, const Configuration& config);
GdalRawTileDataReader(const std::string& filePath, const Configuration& config,
const std::string& baseDirectory = "");
virtual ~GdalRawTileDataReader() override;

View File

@@ -105,6 +105,10 @@ GdalWrapper::GdalWrapper(size_t maximumCacheSize,
"GDAL_DATA",
absPath("${MODULE_GLOBEBROWSING}/gdal_data").c_str()
);
CPLSetConfigOption(
"CPL_TMPDIR",
absPath("${BASE_PATH}").c_str()
);
setGdalProxyConfiguration();
CPLSetErrorHandler(gdalErrorHandler);

View File

@@ -132,9 +132,9 @@ TileDepthTransform RawTileDataReader::getDepthTransform() const {
std::array<double, 6> RawTileDataReader::getGeoTransform() const {
std::array<double, 6> padfTransform;
GeodeticPatch globalCoverage(Geodetic2(0,0), Geodetic2(M_PI / 2.0, M_PI));
padfTransform[1] = Angle<double>::fromRadians(
padfTransform[1] = Angle<double>::fromRadians(
globalCoverage.size().lon).asDegrees() / rasterXSize();
padfTransform[5] = -Angle<double>::fromRadians(
globalCoverage.size().lat).asDegrees() / rasterYSize();

View File

@@ -51,42 +51,42 @@ public:
* Describe if this Tile is good for usage (OK) or otherwise
* the reason why it is not.
*/
enum class Status {
/**
* E.g when texture data is not currently in memory.
* texture and tileMetaData are both null
*/
Unavailable,
enum class Status {
/**
* E.g when texture data is not currently in memory.
* texture and tileMetaData are both null
*/
Unavailable,
/**
* Can be set by <code>TileProvider</code>s if the requested
* <code>TileIndex</code> is undefined for that particular
* provider.
* texture and metaData are both null
*/
OutOfRange,
/**
* Can be set by <code>TileProvider</code>s if the requested
* <code>TileIndex</code> is undefined for that particular
* provider.
* texture and metaData are both null
*/
OutOfRange,
/**
* An IO Error happend
* texture and metaData are both null
*/
IOError,
/**
* An IO Error happend
* texture and metaData are both null
*/
IOError,
/**
* The Texture is uploaded to the GPU and good for usage.
* texture is defined. metaData may be defined.
*/
OK
};
/**
* The Texture is uploaded to the GPU and good for usage.
* texture is defined. metaData may be defined.
*/
OK
};
Tile(std::shared_ptr<ghoul::opengl::Texture> texture,
std::shared_ptr<TileMetaData> metaData,
Status status);
~Tile() = default;
std::shared_ptr<TileMetaData> metaData() const { return _metaData; };
Status status() const { return _status; };
std::shared_ptr<ghoul::opengl::Texture> texture() const { return _texture; };
std::shared_ptr<TileMetaData> metaData() const { return _metaData; };
Status status() const { return _status; };
std::shared_ptr<ghoul::opengl::Texture> texture() const { return _texture; };
/**
* Instantiates a new tile with a single color.
@@ -102,16 +102,16 @@ public:
glm::vec2 sizeDiff, glm::uvec2 resolution, glm::vec2 tileUV);
static glm::vec2 TileUvToTextureSamplePosition(const TileUvTransform& uvTransform,
glm::vec2 tileUV, glm::uvec2 resolution);
/**
* A tile with status unavailable that any user can return to
* indicate that a tile was unavailable.
*/
static const Tile TileUnavailable;
/**
* A tile with status unavailable that any user can return to
* indicate that a tile was unavailable.
*/
static const Tile TileUnavailable;
private:
std::shared_ptr<ghoul::opengl::Texture> _texture;
std::shared_ptr<TileMetaData> _metaData;
Status _status;
std::shared_ptr<ghoul::opengl::Texture> _texture;
std::shared_ptr<TileMetaData> _metaData;
Status _status;
};
} // namespace globebrowsing

View File

@@ -40,7 +40,9 @@ namespace {
const char* KeyDoPreProcessing = "DoPreProcessing";
const char* KeyTilePixelSize = "TilePixelSize";
const char* KeyFilePath = "FilePath";
const char* KeyBasePath = "BasePath";
const char* KeyFlushInterval = "FlushInterval";
const char* KeyPreCacheLevel = "PreCacheLevel";
}
namespace openspace {
@@ -50,7 +52,7 @@ namespace tileprovider {
CachingTileProvider::CachingTileProvider(const ghoul::Dictionary& dictionary)
: TileProvider(dictionary)
, _framesSinceLastRequestFlush(0)
, _defaultTile(Tile::TileUnavailable)
, _defaultTile(Tile::TileUnavailable)
{
std::string name = "Name unspecified";
dictionary.getValue("Name", name);
@@ -84,9 +86,12 @@ CachingTileProvider::CachingTileProvider(const ghoul::Dictionary& dictionary)
framesUntilRequestFlush);
}
std::string basePath;
dictionary.getValue(KeyBasePath, basePath);
// Initialize instance variables
#ifdef GLOBEBROWSING_USE_GDAL
auto tileDataset = std::make_shared<GdalRawTileDataReader>(filePath, config);
auto tileDataset = std::make_shared<GdalRawTileDataReader>(filePath, config, basePath);
#else // GLOBEBROWSING_USE_GDAL
auto tileDataset = std::make_shared<SimpleRawTileDataReader>(filePath, config);
#endif // GLOBEBROWSING_USE_GDAL
@@ -99,6 +104,18 @@ CachingTileProvider::CachingTileProvider(const ghoul::Dictionary& dictionary)
_asyncTextureDataProvider = std::make_shared<AsyncTileDataProvider>(
tileDataset, threadPool);
_framesUntilRequestFlush = framesUntilRequestFlush;
if (dictionary.hasKeyAndValue<double>(KeyPreCacheLevel)) {
int preCacheLevel = static_cast<int>(dictionary.value<double>(KeyPreCacheLevel));
LDEBUG("Precaching '" << filePath << "' with level '" << preCacheLevel << "'");
for (int level = 0; level <= preCacheLevel; ++level) {
for (int x = 0; x <= level * 2; ++x) {
for (int y = 0; y <= level; ++y) {
_asyncTextureDataProvider->enqueueTileIO({ x, y, level });
}
}
}
}
}
CachingTileProvider::CachingTileProvider(

View File

@@ -0,0 +1,118 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2016 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#include <modules/globebrowsing/geometry/geodetic2.h>
#include <modules/globebrowsing/tile/tileprovider/presentationslideprovider.h>
#include <modules/globebrowsing/tile/tileindex.h>
#include <ghoul/io/texture/texturereader.h>
#include <ghoul/filesystem/filesystem.h>
#include <ghoul/logging/logmanager.h>
#include <openspace/engine/openspaceengine.h>
namespace {
const std::string _loggerCat = "PresentationSlideProvider";
const std::string KeyDefaultProvider = "DefaultProvider";
const std::string KeySlideProviders = "SlideProviders";
const std::string KeyTileIndex = "TileIndex";
const std::string KeyTileProvider = "TileProvider";
}
namespace openspace {
namespace globebrowsing {
namespace tileprovider {
PresentationSlideProvider::PresentationSlideProvider(const ghoul::Dictionary& dictionary)
: _slideIndex("slideIndex", "slideIndex", 0, 0, _slideProviders.size() - 1)
{
setName("SlideProvider");
ghoul::Dictionary defaultProviderDict = dictionary.value<ghoul::Dictionary>(KeyDefaultProvider);
_defaultProvider = TileProvider::createFromDictionary(defaultProviderDict);
ghoul::Dictionary tileIndexDict = dictionary.value<ghoul::Dictionary>(KeyTileIndex);
_tileIndex = TileIndex(tileIndexDict);
ghoul::Dictionary slideProvidersDict = dictionary.value<ghoul::Dictionary>(KeySlideProviders);
_slideProviders.resize(slideProvidersDict.size());
for (size_t i = 0; i < slideProvidersDict.size(); i++) {
std::string dictKey = std::to_string(i + 1);
ghoul::Dictionary providerDict = slideProvidersDict.value<ghoul::Dictionary>(dictKey);
_slideProviders[i] = TileProvider::createFromDictionary(providerDict);
}
_slideIndex.setMaxValue(_slideProviders.size() - 1);
addProperty(_slideIndex);
}
Tile PresentationSlideProvider::getTile(const TileIndex& tileIndex) {
if(tileIndex == _tileIndex){
return slideProvider()->getTile(tileIndex);
}
return Tile::TileUnavailable;
}
Tile PresentationSlideProvider::getDefaultTile() {
return _defaultProvider->getDefaultTile();
}
Tile::Status PresentationSlideProvider::getTileStatus(const TileIndex& tileIndex) {
if(tileIndex == _tileIndex){
return slideProvider()->getTileStatus(tileIndex);
}
return Tile::Status::Unavailable;
}
TileDepthTransform PresentationSlideProvider::depthTransform() {
return slideProvider()->depthTransform();
}
void PresentationSlideProvider::update() {
slideProvider()->update();
_defaultProvider->update();
}
void PresentationSlideProvider::reset() {
for(auto& tp : _slideProviders){
tp->reset();
}
_defaultProvider->reset();
}
int PresentationSlideProvider::maxLevel() {
return _defaultProvider->maxLevel();
}
TileProvider* PresentationSlideProvider::slideProvider() {
int maxIndex = (int)_slideProviders.size() - 1;
int clampedIndex = std::max(0, std::min(_slideIndex.value(), maxIndex));
_slideIndex.setValue(clampedIndex);
return _slideProviders[clampedIndex].get();
}
} // namespace tileprovider
} // namespace globebrowsing
} // namespace openspace

View File

@@ -0,0 +1,70 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2016 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#ifndef __PRESENTATION_SLIDE_PROVIDER__
#define __PRESENTATION_SLIDE_PROVIDER__
#include <modules/globebrowsing/geometry/geodetic2.h>
#include <modules/globebrowsing/tile/tileprovider/tileprovider.h>
#include <ghoul/logging/logmanager.h>
#include <ghoul/opengl/texture.h>
#include <openspace/properties/scalarproperty.h>
#include <memory>
#include <unordered_map>
namespace openspace {
namespace globebrowsing {
namespace tileprovider {
class PresentationSlideProvider : public TileProvider {
public:
PresentationSlideProvider(const ghoul::Dictionary& dictionary);
PresentationSlideProvider(const std::string& imagePath);
virtual ~PresentationSlideProvider() { }
virtual Tile getTile(const TileIndex& tileIndex);
virtual Tile getDefaultTile();
virtual Tile::Status getTileStatus(const TileIndex& index);
virtual TileDepthTransform depthTransform();
virtual void update();
virtual void reset();
virtual int maxLevel();
private:
TileProvider* slideProvider();
TileIndex _tileIndex;
properties::IntProperty _slideIndex;
std::vector<std::unique_ptr<TileProvider>> _slideProviders;
std::unique_ptr<TileProvider> _defaultProvider;
};
} // namespace tileprovider
} // namespace globebrowsing
} // namespace openspace
#endif // __PRESENTATION_SLIDE_PROVIDER__

View File

@@ -112,7 +112,7 @@ documentation::Documentation ProjectionTileProvider::Documentation() {
ProjectionTileProvider::ProjectionTileProvider(const ghoul::Dictionary& dictionary)
: _fboProgramObject(nullptr)
, _capture(false)
, _defaultTile(Tile::TileUnavailable)
, _defaultTile(Tile::TileUnavailable)
{
ghoul::Dictionary geometryDictionary;

View File

@@ -49,7 +49,7 @@ SingleImageProvider::SingleImageProvider(const ghoul::Dictionary& dictionary)
SingleImageProvider::SingleImageProvider(const std::string& imagePath)
: _imagePath(imagePath)
, _tile(nullptr, nullptr, Tile::Status::Unavailable)
, _tile(nullptr, nullptr, Tile::Status::Unavailable)
{
reset();
}
@@ -87,7 +87,7 @@ void SingleImageProvider::reset() {
tileTexture->uploadTexture();
tileTexture->setFilter(ghoul::opengl::Texture::FilterMode::Linear);
_tile = Tile(tileTexture, tileMetaData, tileStatus);
_tile = Tile(tileTexture, tileMetaData, tileStatus);
}
int SingleImageProvider::maxLevel() {

View File

@@ -46,7 +46,7 @@ namespace {
}
SizeReferenceTileProvider::SizeReferenceTileProvider(const ghoul::Dictionary& dictionary)
: _backgroundTile(Tile::TileUnavailable)
: _backgroundTile(Tile::TileUnavailable)
{
_fontSize = 50;
_font = OsEng.fontManager().font("Mono", _fontSize);
@@ -58,9 +58,9 @@ SizeReferenceTileProvider::SizeReferenceTileProvider(const ghoul::Dictionary& di
_ellipsoid = Ellipsoid(radii);
auto backgroundTileStatus = Tile::Status::Unavailable;
std::shared_ptr<ghoul::opengl::Texture> backgroundTileTexture;
std::shared_ptr<ghoul::opengl::Texture> backgroundTileTexture;
std::string backgroundImagePath;
std::string backgroundImagePath;
if (dictionary.getValue(KeyBackgroundImagePath, backgroundImagePath)) {
using namespace ghoul::io;
std::string imgAbsPath = absPath(backgroundImagePath);
@@ -69,7 +69,7 @@ SizeReferenceTileProvider::SizeReferenceTileProvider(const ghoul::Dictionary& di
backgroundTileTexture->setFilter(ghoul::opengl::Texture::FilterMode::Linear);
backgroundTileStatus = Tile::Status::OK;
}
_backgroundTile = Tile(backgroundTileTexture, nullptr, backgroundTileStatus);
_backgroundTile = Tile(backgroundTileTexture, nullptr, backgroundTileStatus);
}
void SizeReferenceTileProvider::renderText(const ghoul::fontrendering::FontRenderer&

View File

@@ -41,8 +41,11 @@ namespace {
const char* KeyDoPreProcessing = "DoPreProcessing";
const char* KeyMinimumPixelSize = "MinimumPixelSize";
const char* KeyFilePath = "FilePath";
const char* KeyBasePath = "BasePath";
const char* KeyCacheSize = "CacheSize";
const char* KeyFlushInterval = "FlushInterval";
const char* KeyPreCacheStartTime = "PreCacheStartTime";
const char* KeyPreCacheEndTime = "PreCacheEndTime";
}
namespace openspace {
@@ -64,6 +67,8 @@ TemporalTileProvider::TemporalTileProvider(const ghoul::Dictionary& dictionary)
throw std::runtime_error(std::string("Must define key '") + KeyFilePath + "'");
}
_datasetFile = absPath(_datasetFile);
std::ifstream in(_datasetFile.c_str());
if (!in.is_open()) {
throw ghoul::FileNotFoundError(_datasetFile);
@@ -74,7 +79,29 @@ TemporalTileProvider::TemporalTileProvider(const ghoul::Dictionary& dictionary)
std::istreambuf_iterator<char>(in),
(std::istreambuf_iterator<char>())
);
_initDict.setValue<std::string>(
KeyBasePath,
ghoul::filesystem::File(_datasetFile).directoryName()
);
_gdalXmlTemplate = consumeTemporalMetaData(xml);
const bool hasStart = dictionary.hasKeyAndValue<std::string>(KeyPreCacheStartTime);
const bool hasEnd = dictionary.hasKeyAndValue<std::string>(KeyPreCacheEndTime);
if (hasStart && hasEnd) {
const std::string start = dictionary.value<std::string>(KeyPreCacheStartTime);
const std::string end = dictionary.value<std::string>(KeyPreCacheEndTime);
std::vector<Time> preCacheTimes = _timeQuantizer.quantized(
Time(Time::convertTime(start)),
Time(Time::convertTime(end))
);
LINFO("Preloading: " << _datasetFile);
for (Time& t : preCacheTimes) {
getTileProvider(t);
}
}
}
std::string TemporalTileProvider::consumeTemporalMetaData(const std::string& xml) {
@@ -166,7 +193,7 @@ Tile TemporalTileProvider::getTile(const TileIndex& tileIndex) {
}
Tile TemporalTileProvider::getDefaultTile() {
return getTileProvider()->getDefaultTile();
return getTileProvider()->getDefaultTile();
}
int TemporalTileProvider::maxLevel() {
@@ -228,33 +255,20 @@ std::shared_ptr<TileProvider> TemporalTileProvider::getTileProvider(TimeKey time
}
std::shared_ptr<TileProvider> TemporalTileProvider::initTileProvider(TimeKey timekey) {
static const std::vector<std::string> AllowedToken = {
// From: http://www.gdal.org/frmt_wms.html
// @FRAGILE: What happens if a user specifies one of these as path tokens?
// ---abock
"${x}",
"${y}",
"${z}",
"${version}",
"${format}",
"${layer}"
};
std::string gdalDatasetXml = getGdalDatasetXML(timekey);
try {
gdalDatasetXml = absPath(gdalDatasetXml);
}
catch (ghoul::filesystem::FileSystem::ResolveTokenException& e) {
const std::vector<std::string> AllowedToken = {
// From: http://www.gdal.org/frmt_wms.html
// @FRAGILE: What happens if a user specifies one of these as path tokens?
// ---abock
"${x}",
"${y}",
"${z}",
"${version}",
"${format}",
"${layer}"
};
auto it = std::find(AllowedToken.begin(), AllowedToken.end(), e.token);
if (it == AllowedToken.end()) {
throw;
}
LINFOC(
"TemporalTileProvider",
fmt::format("Ignoring '{}' in absolute path resolve", e.token)
);
}
FileSys.expandPathTokens(gdalDatasetXml, AllowedToken);
_initDict.setValue<std::string>(KeyFilePath, gdalDatasetXml);
auto tileProvider = std::make_shared<CachingTileProvider>(_initDict);
@@ -282,6 +296,16 @@ std::string YYYY_MM_DD::stringify(const Time& t) const {
return t.ISO8601().substr(0, 10);
}
std::string YYYYMMDD_hhmmss::stringify(const Time& t) const {
std::string ts = t.ISO8601().substr(0, 19);
// YYYY_MM_DDThh_mm_ss -> YYYYMMDD_hhmmss
ts.erase(std::remove(ts.begin(), ts.end(), '-'), ts.end());
ts.erase(std::remove(ts.begin(), ts.end(), ':'), ts.end());
replace(ts.begin(), ts.end(), 'T', '_');
return ts;
}
std::string YYYY_MM_DDThhColonmmColonssZ::stringify(const Time& t) const {
return t.ISO8601().substr(0, 19) + "Z";
}
@@ -305,10 +329,12 @@ void TimeIdProviderFactory::init() {
_timeIdProviderMap.insert(std::pair<std::string, std::unique_ptr<TimeFormat>>(
{ "YYYY-MM-DDThh:mm:ssZ", std::make_unique<YYYY_MM_DDThhColonmmColonssZ>() }
));
initialized = true;
_timeIdProviderMap.insert(std::pair<std::string, std::unique_ptr<TimeFormat>>(
{ "YYYY-MM-DDThh_mm_ssZ", std::make_unique<YYYY_MM_DDThh_mm_ssZ>() }
));
_timeIdProviderMap.insert(std::pair<std::string, std::unique_ptr<TimeFormat>>(
{ "YYYYMMDD_hhmmss", std::make_unique<YYYYMMDD_hhmmss>() }
));
initialized = true;
}
@@ -379,6 +405,28 @@ bool TimeQuantizer::quantize(Time& t, bool clamp) const {
}
}
std::vector<Time> TimeQuantizer::quantized(const Time& start, const Time& end) const {
Time s = start;
quantize(s, true);
Time e = end;
quantize(e, true);
const double startSeconds = s.j2000Seconds();
const double endSeconds = e.j2000Seconds();
const double delta = endSeconds - startSeconds;
ghoul_assert(int(delta) % int(_resolution) == 0, "Quantization error");
const int nSteps = delta / _resolution;
std::vector<Time> result(nSteps + 1);
for (int i = 0; i <= nSteps; ++i) {
result[i].setTime(startSeconds + i * _resolution, false);
}
return result;
}
} // namespace tileprovider
} // namespace globebrowsing
} // namespace openspace

View File

@@ -66,6 +66,14 @@ struct YYYY_MM_DD : public TimeFormat {
virtual std::string stringify(const Time& t) const;
};
/**
* Stringifies OpenSpace to the format "YYYYMMDD_hhmmss"
* Example: 20160908_230505
*/
struct YYYYMMDD_hhmmss : public TimeFormat {
virtual std::string stringify(const Time& t) const;
};
/**
* Stringifies OpenSpace to the format "YYYY-MM-DDThh:mm:ssZ"
* Example: 2016-09-08T23:05:05Z
@@ -143,6 +151,15 @@ struct TimeQuantizer {
*/
bool quantize(Time& t, bool clamp) const;
/**
* Returns a list of quantized Time objects that represent all the valid quantized
* Time%s between \p start and \p end.
* \param start The start time for the time range quantization
* \param end The end time for the time range quantization
* \return A list of quantized times between \p start and \end
*/
std::vector<Time> quantized(const Time& start, const Time& end) const;
private:
TimeRange _timerange;
double _resolution;

View File

@@ -34,8 +34,6 @@
#include <climits>
namespace {
const std::string _loggerCat = "TileProvider";
const char* KeyType = "Type";
}
@@ -50,18 +48,13 @@ std::unique_ptr<TileProvider> TileProvider::createFromDictionary(const ghoul::Di
dictionary.getValue(KeyType, type);
auto factory = FactoryManager::ref().factory<TileProvider>();
std::unique_ptr<TileProvider> result = factory->create(type, dictionary);
if (result == nullptr) {
LERROR("Failed creating TileProvider of type '" << type << "'");
return nullptr;
}
return result;
}
TileProvider::TileProvider() :
properties::PropertyOwner("tileProvider"),
_initialized(false) {
TileProvider::TileProvider()
: properties::PropertyOwner("tileProvider")
, _initialized(false)
{
initialize();
}

View File

@@ -41,10 +41,10 @@ namespace tileselector {
ChunkTile getHighestResolutionTile(const LayerGroup& layerGroup, const TileIndex& tileIndex);
std::vector<ChunkTile> getTilesSortedByHighestResolution(const LayerGroup& layerGroup,
const TileIndex& tileIndex);
const TileIndex& tileIndex);
std::vector<std::pair<ChunkTile, const LayerRenderSettings*> >
getTilesAndSettingsSortedByHighestResolution(const LayerGroup& layerGroup,
const TileIndex& tileIndex);
getTilesAndSettingsSortedByHighestResolution(const LayerGroup& layerGroup,
const TileIndex& tileIndex);
void ascendToParent(TileIndex& tileIndex, TileUvTransform& uv);

View File

@@ -109,7 +109,7 @@ void KameleonDocumentationTask::perform(const Task::ProgressCallback & progressC
file.exceptions(~std::ofstream::goodbit);
file.open(_outputPath);
std::stringstream html;
std::stringstream html;
html << "<!DOCTYPE html>\n"
<< "<html>\n"
<< "\t<head>\n"

View File

@@ -30,6 +30,7 @@ set(HEADER_FILES
${CMAKE_CURRENT_SOURCE_DIR}/include/guihelpcomponent.h
${CMAKE_CURRENT_SOURCE_DIR}/include/guiorigincomponent.h
${CMAKE_CURRENT_SOURCE_DIR}/include/guiperformancecomponent.h
${CMAKE_CURRENT_SOURCE_DIR}/include/guiparallelcomponent.h
${CMAKE_CURRENT_SOURCE_DIR}/include/guipropertycomponent.h
${CMAKE_CURRENT_SOURCE_DIR}/include/guitimecomponent.h
${CMAKE_CURRENT_SOURCE_DIR}/include/guiiswacomponent.h
@@ -44,6 +45,7 @@ set(SOURCE_FILES
${CMAKE_CURRENT_SOURCE_DIR}/src/guihelpcomponent.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/guiorigincomponent.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/guiperformancecomponent.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/guiparallelcomponent.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/guipropertycomponent.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/guitimecomponent.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/guiiswacomponent.cpp

View File

@@ -32,6 +32,7 @@
#include <modules/onscreengui/include/guiorigincomponent.h>
#include <modules/onscreengui/include/guitimecomponent.h>
#include <modules/onscreengui/include/guiiswacomponent.h>
#include <modules/onscreengui/include/guiparallelcomponent.h>
#include <openspace/scripting/scriptengine.h>
#include <openspace/properties/property.h>
@@ -72,6 +73,7 @@ public:
GuiPropertyComponent _virtualProperty;
GuiTimeComponent _time;
GuiIswaComponent _iswa;
GuiParallelComponent _parallel;
private:
void renderAndUpdatePropertyVisibility();

View File

@@ -0,0 +1,51 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2017 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#ifndef __OPENSPACE_MODULE_ONSCREENGUI___GUIPARALLELCOMPONENT___H__
#define __OPENSPACE_MODULE_ONSCREENGUI___GUIPARALLELCOMPONENT___H__
#include <modules/onscreengui/include/guicomponent.h>
#include <modules/onscreengui/include/guipropertycomponent.h>
#include <string>
namespace openspace {
namespace gui {
class GuiParallelComponent : public GuiPropertyComponent {
public:
GuiParallelComponent();
void render() override;
private:
void renderDisconnected();
void renderClientWithHost();
void renderClientWithoutHost();
void renderClientCommon();
void renderHost();
};
} // namespace gui
} // namespace openspace
#endif // __OPENSPACE_MODULE_ONSCREENGUI___GUIPARALLELCOMPONENT___H__

View File

@@ -31,6 +31,7 @@
#include <openspace/engine/virtualpropertymanager.h>
#include <openspace/engine/wrapper/windowwrapper.h>
#include <openspace/interaction/interactionhandler.h>
#include <openspace/network/parallelconnection.h>
#include <openspace/rendering/renderengine.h>
#include <openspace/rendering/screenspacerenderable.h>
#include <openspace/scene/scene.h>
@@ -59,7 +60,8 @@ OnScreenGUIModule::OnScreenGUIModule()
&(OsEng.windowWrapper()),
&(OsEng.settingsEngine()),
&(OsEng.interactionHandler()),
&(OsEng.renderEngine())
&(OsEng.renderEngine()),
&(OsEng.parallelConnection())
};
return res;
}
@@ -118,11 +120,14 @@ OnScreenGUIModule::OnScreenGUIModule()
);
OsEng.registerModuleCallback(
OpenSpaceEngine::CallbackOption::Render,
// This is done in the PostDraw phase so that it will render it on top of
// everything else in the case of fisheyes. With this being in the Render callback
// the GUI would be rendered on top of each of the cube faces
OpenSpaceEngine::CallbackOption::PostDraw,
[](){
WindowWrapper& wrapper = OsEng.windowWrapper();
bool showGui = wrapper.hasGuiWindow() ? wrapper.isGuiWindow() : true;
if (wrapper.isMaster() && wrapper.isRegularRendering() && showGui ) {
if (wrapper.isMaster() && showGui ) {
glm::vec2 mousePosition = wrapper.mousePosition();
//glm::ivec2 drawBufferResolution = _windowWrapper->currentDrawBufferResolution();
glm::ivec2 windowSize = wrapper.currentWindowSize();

View File

@@ -322,6 +322,7 @@ void GUI::initialize() {
_virtualProperty.initialize();
_performance.initialize();
_help.initialize();
_parallel.initialize();
_iswa.initialize();
}
@@ -329,6 +330,7 @@ void GUI::deinitialize() {
ImGui::Shutdown();
_iswa.deinitialize();
_parallel.deinitialize();
_help.deinitialize();
_performance.deinitialize();
_globalProperty.deinitialize();
@@ -408,6 +410,7 @@ void GUI::initializeGL() {
_globalProperty.initializeGL();
_performance.initializeGL();
_help.initializeGL();
_parallel.initializeGL();
_iswa.initializeGL();
}
@@ -426,6 +429,7 @@ void GUI::deinitializeGL() {
}
_iswa.deinitializeGL();
_parallel.deinitializeGL();
_help.deinitializeGL();
_performance.deinitializeGL();
_globalProperty.deinitializeGL();
@@ -471,14 +475,15 @@ void GUI::endFrame() {
if (_screenSpaceProperty.isEnabled()) {
_screenSpaceProperty.render();
}
if (_virtualProperty.isEnabled()) {
_virtualProperty.render();
}
if (_help.isEnabled()) {
_help.render();
}
if (_parallel.isEnabled()) {
_parallel.render();
}
if (_iswa.isEnabled()) {
_iswa.render();
}
@@ -570,6 +575,10 @@ void GUI::render() {
ImGui::Checkbox("Global Properties", &globalProperty);
_globalProperty.setEnabled(globalProperty);
bool parallel = _parallel.isEnabled();
ImGui::Checkbox("Parallel Connection", &parallel);
_parallel.setEnabled(parallel);
bool virtualProperty = _virtualProperty.isEnabled();
ImGui::Checkbox("Virtual Properties", &virtualProperty);
_virtualProperty.setEnabled(virtualProperty);

View File

@@ -0,0 +1,191 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2017 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#include <modules/onscreengui/include/guiparallelcomponent.h>
#include <openspace/engine/openspaceengine.h>
#include <openspace/util/timemanager.h>
#include <openspace/interaction/interactionhandler.h>
#include <openspace/network/parallelconnection.h>
#include <openspace/network/messagestructures.h>
#include <imgui.h>
#include <fmt/format.h>
#include <algorithm>
#include <numeric>
namespace {
const std::string _loggerCat = "GuiParallelComponent";
}
namespace openspace {
namespace gui {
GuiParallelComponent::GuiParallelComponent()
: GuiPropertyComponent("GuiParallelComponent")
{
setVisibility(properties::Property::Visibility::All);
}
void GuiParallelComponent::renderDisconnected() {
ImGui::Text("Not connected");
const bool connect = ImGui::Button("Connect");
if (connect) {
OsEng.parallelConnection().clientConnect();
}
}
void GuiParallelComponent::renderClientWithHost() {
ParallelConnection& parallel = OsEng.parallelConnection();
std::string connectionInfo = "Session hosted by \"" + parallel.hostName() + "\"\n";
size_t nConnections = parallel.nConnections();
size_t nClients = nConnections - 1;
if (nClients > 2) {
std::string c = std::to_string(nClients - 1);
connectionInfo += "You and " + c + " more clients are connected";
}
else if (nClients == 2) {
std::string c = std::to_string(nClients - 1);
connectionInfo += "You and " + c + " more client are connected";
}
else if (nClients == 1) {
connectionInfo += "You are the only client";
}
ImGui::Text(connectionInfo.c_str());
renderClientCommon();
const std::deque<datamessagestructures::TimeKeyframe> timeKeyframes = OsEng.timeManager().keyframes();
const std::vector<datamessagestructures::CameraKeyframe> cameraKeyframes = OsEng.interactionHandler().keyframes();
std::string timeKeyframeInfo = "TimeKeyframes : " + std::to_string(timeKeyframes.size());
std::string cameraKeyframeInfo = "CameraKeyframes : " + std::to_string(cameraKeyframes.size());
std::string latencyStandardDeviation = "Latency standard deviation: " + std::to_string(parallel.latencyStandardDeviation()) + " s";
const bool resetTimeOffset = ImGui::Button("Reset time offset");
if (resetTimeOffset) {
parallel.resetTimeOffset();
}
ImGui::Text(timeKeyframeInfo.c_str());
ImGui::Text(cameraKeyframeInfo.c_str());
ImGui::Text(latencyStandardDeviation.c_str());
}
void GuiParallelComponent::renderClientWithoutHost() {
ParallelConnection& parallel = OsEng.parallelConnection();
std::string connectionInfo = "Connected to parallel session with no host\n";
size_t nConnections = parallel.nConnections();
if (nConnections > 2) {
std::string c = std::to_string(nConnections - 1);
connectionInfo += "You and " + c + " more users are connected";
}
else if (nConnections == 2) {
std::string c = std::to_string(nConnections - 1);
connectionInfo += "You and " + c + " more users are connected";
}
else if (nConnections == 1) {
connectionInfo += "You are the only one here";
}
ImGui::Text(connectionInfo.c_str());
renderClientCommon();
}
void GuiParallelComponent::renderClientCommon() {
ParallelConnection& parallel = OsEng.parallelConnection();
bool requestHostship = ImGui::Button("Request hostship");
const bool disconnect = ImGui::Button("Disconnect");
if (requestHostship) {
parallel.requestHostship();
}
if (disconnect) {
parallel.signalDisconnect();
}
}
void GuiParallelComponent::renderHost() {
ParallelConnection& parallel = OsEng.parallelConnection();
size_t nConnections = parallel.nConnections();
std::string connectionInfo = "";
size_t nClients = nConnections - 1;
if (nClients == 1) {
connectionInfo = "Hosting session with 1 client";
} else {
connectionInfo =
"Hosting session with " + std::to_string(nClients) + " clients";
}
ImGui::Text(connectionInfo.c_str());
const bool resignHostship = ImGui::Button("Resign hostship");
if (resignHostship) {
parallel.resignHostship();
}
}
void GuiParallelComponent::render() {
bool v = _isEnabled;
ImGui::Begin("Parallel Connection", &v);
_isEnabled = v;
ParallelConnection::Status status = OsEng.parallelConnection().status();
switch (status) {
case ParallelConnection::Status::Disconnected:
renderDisconnected();
break;
case ParallelConnection::Status::ClientWithHost:
renderClientWithHost();
break;
case ParallelConnection::Status::ClientWithoutHost:
renderClientWithoutHost();
break;
case ParallelConnection::Status::Host:
renderHost();
break;
}
GuiPropertyComponent::renderPropertyOwner(&OsEng.parallelConnection());
ImGui::End();
}
} // namespace gui
} // namespace openspace

View File

@@ -91,7 +91,16 @@ return {
-- OnScreenTextScaling = "framebuffer",
-- PerSceneCache = true,
-- DisableRenderingOnMaster = true,
KeyDisableSceneOnMaster = true,
DownloadRequestURL = "http://data.openspaceproject.com/request.cgi",
RenderingMethod = "Framebuffer"
RenderingMethod = "Framebuffer",
OpenGLDebugContext = {
Activate = true,
FilterIdentifier = {
{ Type = "Other", Source = "API", Identifier = 131185 }
},
-- FilterSeverity = { }
}
--RenderingMethod = "ABuffer" -- alternative: "Framebuffer"
}

View File

@@ -206,6 +206,14 @@ std::string StringListVerifier::type() const {
return "List of strings";
}
IntListVerifier::IntListVerifier(std::string elementDocumentation)
: TableVerifier({ { "*", new IntVerifier, std::move(elementDocumentation) } })
{}
std::string IntListVerifier::type() const {
return "List of ints";
}
ReferencingVerifier::ReferencingVerifier(std::string id)
: identifier(std::move(id))
{

View File

@@ -73,6 +73,7 @@ const string ConfigurationManager::KeyCapabilitiesVerbosity =
const string ConfigurationManager::KeyShutdownCountdown = "ShutdownCountdown";
const string ConfigurationManager::KeyDisableMasterRendering = "DisableRenderingOnMaster";
const string ConfigurationManager::KeyDisableSceneOnMaster = "DisableSceneOnMaster";
const string ConfigurationManager::KeyDownloadRequestURL = "DownloadRequestURL";
const string ConfigurationManager::KeyPerSceneCache = "PerSceneCache";
const string ConfigurationManager::KeyRenderingMethod = "RenderingMethod";
@@ -86,6 +87,15 @@ const string ConfigurationManager::PartHttpProxyAuthentication = "Authentication
const string ConfigurationManager::PartHttpProxyUser = "User";
const string ConfigurationManager::PartHttpProxyPassword = "Password";
const string ConfigurationManager::KeyOpenGLDebugContext = "OpenGLDebugContext";
const string ConfigurationManager::PartActivate = "Activate";
const string ConfigurationManager::PartSynchronous = "Synchronous";
const string ConfigurationManager::PartFilterIdentifier = "FilterIdentifier";
const string ConfigurationManager::PartFilterIdentifierSource = "Source";
const string ConfigurationManager::PartFilterIdentifierType = "Type";
const string ConfigurationManager::PartFilterIdentifierIdentifier = "Identifier";
const string ConfigurationManager::PartFilterSeverity = "PartFilterSeverity";
string ConfigurationManager::findConfiguration(const string& filename) {
using ghoul::filesystem::Directory;

View File

@@ -338,6 +338,16 @@ documentation::Documentation ConfigurationManager::Documentation() {
"the master computer does not have the resources to render a scene.",
Optional::Yes
},
{
ConfigurationManager::KeyDisableSceneOnMaster,
new BoolVerifier,
"Toggles whether a potential scene transformation matrix, for example as "
"specified in an SGCT configuration file, should apply to the master node. "
"With some configurations, applying such a transformation complicates the "
"interaction and it is thus desired to disable the transformation. The "
"default is false.",
Optional::Yes
},
{
ConfigurationManager::KeyHttpProxy,
new TableVerifier({
@@ -375,7 +385,80 @@ documentation::Documentation ConfigurationManager::Documentation() {
"This defines the use for a proxy when fetching data over http."
"No proxy will be used if this is left out.",
Optional::Yes
}
},
{
ConfigurationManager::KeyOpenGLDebugContext,
new TableVerifier({
{
ConfigurationManager::PartActivate,
new BoolVerifier,
"Determines whether the OpenGL context should be a debug context",
Optional::No
},
{
ConfigurationManager::PartSynchronous,
new BoolVerifier,
"Determines whether the OpenGL debug callbacks are performed "
"synchronously. If set to <True> the callbacks are in the same thead "
"as the context and in the scope of the OpenGL function that "
"triggered the message. The default value is <True>.",
Optional::Yes
},
{
ConfigurationManager::PartFilterIdentifier,
new TableVerifier({{
"*",
new TableVerifier({
{
ConfigurationManager::PartFilterIdentifierIdentifier,
new IntVerifier,
"The identifier that is to be filtered",
Optional::No
},
{
ConfigurationManager::PartFilterIdentifierSource,
new StringInListVerifier({
// Taken from ghoul::debugcontext.cpp
"API", "Window System", "Shader Compiler",
"Third Party", "Application", "Other", "Don't care"
}),
"The source of the identifier to be filtered",
Optional::No
},
{
ConfigurationManager::PartFilterIdentifierType,
new StringInListVerifier({
// Taken from ghoul::debugcontext.cpp
"Error", "Deprecated", "Undefined", "Portability",
"Performance", "Marker", "Push group", "Pop group",
"Other", "Don't care"
}),
"The type of the identifier to be filtered"
}
}),
"Individual OpenGL debug message identifiers"
}}),
"A list of OpenGL debug messages identifiers that are filtered",
Optional::Yes
},
{
ConfigurationManager::PartFilterSeverity,
new TableVerifier({
{
"*",
new StringInListVerifier(
// ghoul::debugcontext.cpp
{ "High", "Medium", "Low", "Notification" }
)
}
}),
"A list of severities that can are filtered out",
Optional::Yes
}
}),
"Determines the settings for the creation of an OpenGL debug context.",
Optional::Yes
}
}
};
};

View File

@@ -39,6 +39,7 @@
#include <openspace/interaction/interactionhandler.h>
#include <openspace/interaction/luaconsole.h>
#include <openspace/network/networkengine.h>
#include <openspace/network/parallelconnection.h>
#include <openspace/rendering/renderable.h>
#include <openspace/scripting/scriptscheduler.h>
#include <openspace/scripting/scriptengine.h>
@@ -66,6 +67,7 @@
#include <ghoul/font/fontrenderer.h>
#include <ghoul/logging/consolelog.h>
#include <ghoul/logging/visualstudiooutputlog.h>
#include <ghoul/opengl/debugcontext.h>
#include <ghoul/systemcapabilities/systemcapabilities>
@@ -133,7 +135,7 @@ OpenSpaceEngine::OpenSpaceEngine(
, _settingsEngine(new SettingsEngine)
, _timeManager(new TimeManager)
, _downloadManager(nullptr)
, _parallelConnection(new ParallelConnection)
, _parallelConnection(std::make_unique<ParallelConnection>())
, _windowWrapper(std::move(windowWrapper))
, _globalPropertyNamespace(new properties::PropertyOwner(""))
, _virtualPropertyManager(new VirtualPropertyManager)
@@ -150,7 +152,8 @@ OpenSpaceEngine::OpenSpaceEngine(
_globalPropertyNamespace->addPropertySubOwner(_settingsEngine.get());
_globalPropertyNamespace->addPropertySubOwner(_renderEngine.get());
_globalPropertyNamespace->addPropertySubOwner(_windowWrapper.get());
_globalPropertyNamespace->addPropertySubOwner(_parallelConnection.get());
FactoryManager::initialize();
FactoryManager::ref().addFactory(
std::make_unique<ghoul::TemplateFactory<Renderable>>(),
@@ -369,6 +372,10 @@ void OpenSpaceEngine::create(int argc, char** argv,
}
void OpenSpaceEngine::destroy() {
if (_engine->parallelConnection().status() != ParallelConnection::Status::Disconnected) {
_engine->parallelConnection().signalDisconnect();
}
LTRACE("OpenSpaceEngine::destroy(begin)");
for (const auto& func : _engine->_moduleCallbacks.deinitializeGL) {
func();
@@ -901,6 +908,111 @@ void OpenSpaceEngine::configureLogging() {
void OpenSpaceEngine::initializeGL() {
LTRACE("OpenSpaceEngine::initializeGL(begin)");
const std::string key = ConfigurationManager::KeyOpenGLDebugContext;
if (_configurationManager->hasKey(key)) {
ghoul::Dictionary dict = _configurationManager->value<ghoul::Dictionary>(key);
bool debug = dict.value<bool>(ConfigurationManager::PartActivate);
// Debug output is not available before 4.3
const ghoul::systemcapabilities::Version minVersion = { 4, 3, 0 };
if (OpenGLCap.openGLVersion() < minVersion) {
LINFO("OpenGL Debug context requested, but insufficient version available");
debug = false;
}
if (debug) {
using namespace ghoul::opengl::debug;
bool synchronous = true;
if (dict.hasKey(ConfigurationManager::PartSynchronous)) {
synchronous = dict.value<bool>(ConfigurationManager::PartSynchronous);
}
setDebugOutput(DebugOutput(debug), SynchronousOutput(synchronous));
if (dict.hasKey(ConfigurationManager::PartFilterIdentifier)) {
ghoul::Dictionary filterDict = dict.value<ghoul::Dictionary>(
ConfigurationManager::PartFilterIdentifier
);
for (int i = 1; i <= filterDict.size(); ++i) {
ghoul::Dictionary id = filterDict.value<ghoul::Dictionary>(
std::to_string(i)
);
const unsigned int identifier = static_cast<unsigned int>(
id.value<double>(
ConfigurationManager::PartFilterIdentifierIdentifier
)
);
const std::string s = id.value<std::string>(
ConfigurationManager::PartFilterIdentifierSource
);
const std::string t = id.value<std::string>(
ConfigurationManager::PartFilterIdentifierType
);
setDebugMessageControl(
ghoul::from_string<Source>(s),
ghoul::from_string<Type>(t),
{ identifier },
Enabled::No
);
}
}
if (dict.hasKey(ConfigurationManager::PartFilterSeverity)) {
ghoul::Dictionary filterDict = dict.value<ghoul::Dictionary>(
ConfigurationManager::PartFilterIdentifier
);
for (int i = 1; i <= filterDict.size(); ++i) {
std::string severity = filterDict.value<std::string>(
std::to_string(i)
);
setDebugMessageControl(
Source::DontCare,
Type::DontCare,
ghoul::from_string<Severity>(severity),
Enabled::No
);
}
}
auto callback = [](Source source, Type type, Severity severity,
unsigned int id, std::string message) -> void
{
const std::string s = std::to_string(source);
const std::string t = std::to_string(type);
const std::string category =
"OpenGL (" + s + ") [" + t + "] {" + std::to_string(id) + "}";
switch (severity) {
case Severity::High:
LERRORC(category, std::string(message));
break;
case Severity::Medium:
LWARNINGC(category, std::string(message));
break;
case Severity::Low:
LINFOC(category, std::string(message));
break;
case Severity::Notification:
LDEBUGC(category, std::string(message));
break;
default:
ghoul_assert(false, "Missing case label");
}
};
ghoul::opengl::debug::setDebugCallback(callback);
}
}
LINFO("Initializing Rendering Engine");
// @CLEANUP: Remove the return statement and replace with exceptions ---abock
_renderEngine->initializeGL();
@@ -1025,11 +1137,12 @@ void OpenSpaceEngine::postSynchronizationPreDraw() {
LTRACE("OpenSpaceEngine::postSynchronizationPreDraw(end)");
}
void OpenSpaceEngine::render(const glm::mat4& viewMatrix,
void OpenSpaceEngine::render(const glm::mat4& sceneMatrix,
const glm::mat4& viewMatrix,
const glm::mat4& projectionMatrix)
{
LTRACE("OpenSpaceEngine::render(begin)");
_renderEngine->render(viewMatrix, projectionMatrix);
_renderEngine->render(sceneMatrix, viewMatrix, projectionMatrix);
for (const auto& func : _moduleCallbacks.render) {
func();

View File

@@ -156,13 +156,12 @@ int SGCTWindowWrapper::currentNumberOfAaSamples() const {
}
bool SGCTWindowWrapper::isRegularRendering() const {
// TODO: Needs to implement the nonlinear rendering check ---abock
// sgct::SGCTWindow* w = sgct::Engine::instance()->getCurrentWindowPtr();
// !w->isUsingFisheyeRendering() does not exist anymore ---abock
// if (_isMaster && !w->isUsingFisheyeRendering() && _console->isVisible()) {
return true;
sgct::SGCTWindow* w = sgct::Engine::instance()->getCurrentWindowPtr();
std::size_t nViewports = w->getNumberOfViewports();
ghoul_assert(nViewports > 0, "At least one viewport must exist at this time");
sgct_core::Viewport* vp = w->getViewport(0);
sgct_core::NonLinearProjection* nlp = vp->getNonLinearProjectionPtr();
return nlp == nullptr;
}
bool SGCTWindowWrapper::hasGuiWindow() const {

View File

@@ -39,8 +39,8 @@
#include <ghoul/logging/logmanager.h>
#include <ghoul/misc/interpolator.h>
#include <glm/gtx/quaternion.hpp>
#include <glm/gtx/string_cast.hpp>
#ifdef OPENSPACE_MODULE_GLOBEBROWSING_ENABLED
#include <modules/globebrowsing/geometry/geodetic2.h>
@@ -188,6 +188,10 @@ void InteractionHandler::setInteractionMode(std::shared_ptr<InteractionMode> int
_currentInteractionMode->setFocusNode(focusNode);
}
InteractionMode * InteractionHandler::interactionMode() {
return _currentInteractionMode.get();
}
void InteractionHandler::setInteractionMode(const std::string& interactionModeKey) {
if (_interactionModes.find(interactionModeKey) != _interactionModes.end()) {
setInteractionMode(_interactionModes[interactionModeKey]);
@@ -265,6 +269,15 @@ SceneGraphNode* const InteractionHandler::focusNode() const {
return _currentInteractionMode->focusNode();
}
glm::dvec3 InteractionHandler::focusNodeToCameraVector() const {
return _camera->positionVec3() - focusNode()->worldPosition();
}
glm::quat InteractionHandler::focusNodeToCameraRotation() const {
glm::dmat4 invWorldRotation = glm::inverse(focusNode()->worldRotationMatrix());
return glm::quat(invWorldRotation) * glm::quat(_camera->rotationQuaternion());
}
Camera* const InteractionHandler::camera() const {
return _camera;
}
@@ -625,9 +638,17 @@ void InteractionHandler::addKeyframe(const datamessagestructures::CameraKeyframe
_inputState->addKeyframe(kf);
}
void InteractionHandler::removeKeyframesAfter(double timestamp) {
_inputState->removeKeyframesAfter(timestamp);
}
void InteractionHandler::clearKeyframes() {
_inputState->clearKeyframes();
}
const std::vector<datamessagestructures::CameraKeyframe>& InteractionHandler::keyframes() const {
return _inputState->keyframes();
}
} // namespace interaction
} // namespace openspace

View File

@@ -66,16 +66,21 @@ namespace interaction {
void InputState::addKeyframe(const datamessagestructures::CameraKeyframe &kf) {
clearOldKeyframes();
if (kf._timestamp < OsEng.runTime()) {
return;
}
_keyframes.insert(std::upper_bound(_keyframes.begin(), _keyframes.end(), kf, &InputState::compareKeyframeTimes), kf);
}
auto compareTimestamps = [](const datamessagestructures::CameraKeyframe a,
datamessagestructures::CameraKeyframe b) {
return a._timestamp < b._timestamp;
};
void InputState::removeKeyframesAfter(double timestamp) {
datamessagestructures::CameraKeyframe kf;
kf._timestamp = timestamp;
// Remove keyframes after the inserted keyframe.
_keyframes.erase(std::upper_bound(_keyframes.begin(), _keyframes.end(), kf, compareTimestamps), _keyframes.end());
_keyframes.erase(std::upper_bound(_keyframes.begin(), _keyframes.end(), kf, &InputState::compareKeyframeTimes), _keyframes.end());
}
_keyframes.push_back(kf);
bool InputState::compareKeyframeTimes(const datamessagestructures::CameraKeyframe& a, const datamessagestructures::CameraKeyframe& b) {
return a._timestamp < b._timestamp;
}
void InputState::clearOldKeyframes() {
@@ -170,9 +175,6 @@ namespace interaction {
InteractionMode::InteractionMode()
: _rotateToFocusNodeInterpolator(Interpolator<double>([](double t){
return pow(t, 2);
@@ -242,8 +244,40 @@ void KeyframeInteractionMode::updateCameraStateFromMouseStates(Camera& camera, d
double t = (now - prevTime) / (nextTime - prevTime);
camera.setPositionVec3(prevKeyframe->_position * (1 - t) + nextKeyframe->_position * t);
camera.setRotation(glm::slerp(prevKeyframe->_rotation, nextKeyframe->_rotation, t));
Scene* scene = camera.parent()->scene();
SceneGraphNode* prevFocusNode = scene->sceneGraphNode(prevKeyframe->_focusNode);
SceneGraphNode* nextFocusNode = scene->sceneGraphNode(nextKeyframe->_focusNode);
if (!prevFocusNode || !nextFocusNode) {
return;
}
glm::dvec3 prevKeyframeCameraPosition = prevKeyframe->_position;
glm::dvec3 nextKeyframeCameraPosition = nextKeyframe->_position;
glm::dquat prevKeyframeCameraRotation = prevKeyframe->_rotation;
glm::dquat nextKeyframeCameraRotation = nextKeyframe->_rotation;
// Transform position and rotation based on focus node rotation (if following rotation)
if (prevKeyframe->_followNodeRotation) {
prevKeyframeCameraRotation = prevFocusNode->worldRotationMatrix() * glm::dmat3(prevKeyframe->_rotation);
prevKeyframeCameraPosition = prevFocusNode->worldRotationMatrix() * prevKeyframeCameraPosition;
}
if (nextKeyframe->_followNodeRotation) {
nextKeyframeCameraRotation = nextFocusNode->worldRotationMatrix() * glm::dmat3(nextKeyframe->_rotation);
nextKeyframeCameraPosition = nextFocusNode->worldRotationMatrix() * nextKeyframeCameraPosition;
}
// Transform position based on focus node position
prevKeyframeCameraPosition += prevFocusNode->worldPosition();
nextKeyframeCameraPosition += nextFocusNode->worldPosition();
// Linear interpolation
camera.setPositionVec3(prevKeyframeCameraPosition * (1 - t) + nextKeyframeCameraPosition * t);
camera.setRotation(glm::slerp(prevKeyframeCameraRotation, nextKeyframeCameraRotation, t));
}
bool KeyframeInteractionMode::followingNodeRotation() const {
return false;
}
// OrbitalInteractionMode
@@ -487,6 +521,10 @@ void OrbitalInteractionMode::updateCameraStateFromMouseStates(Camera& camera, do
}
}
bool OrbitalInteractionMode::followingNodeRotation() const {
return false;
}
void OrbitalInteractionMode::updateMouseStatesFromInput(const InputState& inputState, double deltaTime) {
_mouseStates->updateMouseStatesFromInput(inputState, deltaTime);
}
@@ -688,6 +726,10 @@ void GlobeBrowsingInteractionMode::updateCameraStateFromMouseStates(Camera& came
#endif // OPENSPACE_MODULE_GLOBEBROWSING_ENABLED
}
bool GlobeBrowsingInteractionMode::followingNodeRotation() const {
return true;
}
#ifdef OPENSPACE_MODULE_GLOBEBROWSING_ENABLED
void GlobeBrowsingInteractionMode::goToChunk(Camera& camera,
globebrowsing::TileIndex ti, glm::vec2 uv, bool resetCameraDirection) {

View File

@@ -25,6 +25,7 @@
#include <openspace/interaction/luaconsole.h>
#include <openspace/engine/openspaceengine.h>
#include <openspace/network/parallelconnection.h>
#include <ghoul/filesystem/cachemanager.h>
#include <ghoul/filesystem/filesystem.h>
@@ -57,19 +58,13 @@ namespace openspace {
LuaConsole::LuaConsole()
: properties::PropertyOwner("LuaConsole")
, _isVisible("isVisible", "Is Visible", false)
, _remoteScripting(true)
, _remoteScripting("remoteScripting", "Remote scripting", false)
, _inputPosition(0)
, _activeCommand(0)
, _autoCompleteInfo({NoAutoComplete, false, ""})
{
_isVisible.onChange([this](){
if (_isVisible) {
_remoteScripting = false;
} else {
_remoteScripting = OsEng.parallelConnection().isHost();
}
});
addProperty(_isVisible);
addProperty(_remoteScripting);
}
void LuaConsole::initialize() {
@@ -164,7 +159,19 @@ bool LuaConsole::keyboardCallback(Key key, KeyModifier modifier, KeyAction actio
if (key == CommandInputButton) {
// Button left of 1 and above TAB
// How to deal with different keyboard languages? ---abock
_isVisible = !_isVisible;
if (_isVisible) {
if (_remoteScripting) {
_remoteScripting = false;
} else {
_isVisible = false;
}
} else {
_isVisible = true;
if (OsEng.parallelConnection().status() == ParallelConnection::Status::Host) {
_remoteScripting = true;
}
}
return true;
}

View File

@@ -61,14 +61,17 @@
#include <ws2tcpip.h>
#endif
//openspace includes
#include <openspace/network/parallelconnection.h>
#include <openspace/engine/openspaceengine.h>
#include <openspace/engine/wrapper/windowwrapper.h>
#include <openspace/interaction/interactionhandler.h>
#include <openspace/interaction/interactionmode.h>
#include <openspace/scene/scenegraphnode.h>
#include <openspace/util/timemanager.h>
#include <openspace/util/time.h>
#include <openspace/openspace.h>
#include <openspace/scripting/script_helper.h>
#include <ghoul/logging/logmanager.h>
//lua functions
@@ -77,22 +80,26 @@
namespace {
const uint32_t ProtocolVersion = 2;
const size_t MaxLatencyDiffs = 64;
const double BroadcastIntervalMilliseconds = 100;
const std::string _loggerCat = "ParallelConnection";
const int nFrametimesBuffer = 4;
const int nBroadcastIntervalsBuffer = 2;
}
namespace openspace {
ParallelConnection::ParallelConnection()
: _passCode(0)
, _port("20501")
, _address("127.0.0.1")
, _name("Local Connection")
: properties::PropertyOwner("ParallelConnection")
, _password("password", "Password")
, _hostPassword("hostPassword", "Host Password")
, _port("port", "Port", "20501")
, _address("address", "Address", "localhost")
, _name("name", "Connection name", "Anonymous")
, _bufferTime("bufferTime", "Buffer Time", 1, 0.5, 10)
, _timeKeyframeInterval("timeKeyframeInterval", "Time keyframe interval", 0.1, 0, 1)
, _cameraKeyframeInterval("cameraKeyframeInterval", "Camera Keyframe interval", 0.1, 0, 1)
, _timeTolerance("timeTolerance", "Time tolerance", 1, 0.5, 5)
, _lastTimeKeyframeTimestamp(0)
, _lastCameraKeyframeTimestamp(0)
, _clientSocket(INVALID_SOCKET)
, _connectionThread(nullptr)
, _broadcastThread(nullptr)
, _sendThread(nullptr)
, _listenThread(nullptr)
, _handlerThread(nullptr)
@@ -105,6 +112,19 @@ ParallelConnection::ParallelConnection()
, _disconnect(false)
, _initializationTimejumpRequired(false)
{
addProperty(_name);
addProperty(_port);
addProperty(_address);
addProperty(_bufferTime);
addProperty(_password);
addProperty(_hostPassword);
addProperty(_timeKeyframeInterval);
addProperty(_cameraKeyframeInterval);
addProperty(_timeTolerance);
_connectionEvent = std::make_shared<ghoul::Event<>>();
_handlerThread = std::make_unique<std::thread>(&ParallelConnection::threadManagement, this);
}
@@ -186,8 +206,7 @@ void ParallelConnection::disconnect(){
//tell send thread to stop sending and listen thread to stop listenin
_isConnected.store(false);
//tell broadcast thread to stop broadcasting (we're no longer host)
setStatus(Status::Disconnected);
//join connection thread and delete it
@@ -207,13 +226,7 @@ void ParallelConnection::disconnect(){
_listenThread->join();
_listenThread = nullptr;
}
//join broadcast thread and delete it
if(_broadcastThread != nullptr){
_broadcastThread->join();
_broadcastThread = nullptr;
}
// disconnect and cleanup completed
_disconnect = false;
}
@@ -241,7 +254,7 @@ void ParallelConnection::clientConnect(){
hints.ai_flags = AI_PASSIVE;
// Resolve the local address and port to be used by the server
int result = getaddrinfo(_address.c_str(), _port.c_str(), &hints, &addresult);
int result = getaddrinfo(_address.value().c_str(), _port.value().c_str(), &hints, &addresult);
if (result != 0)
{
LERROR("Failed to parse hints for Parallel Connection");
@@ -308,57 +321,39 @@ void ParallelConnection::establishConnection(addrinfo *info){
LERROR("Failed to set socket option 'keep alive'. Error code: " << _ERRNO);
//while the connection thread is still running
while (_tryConnect.load()){
LINFO("Attempting to connect to server "<< _address << " on port " << _port);
LINFO("Attempting to connect to server "<< _address << " on port " << _port);
//try to connect
result = connect(_clientSocket, info->ai_addr, (int)info->ai_addrlen);
//try to connect
result = connect(_clientSocket, info->ai_addr, (int)info->ai_addrlen);
//if the connection was successfull
if (result != SOCKET_ERROR)
{
//if the connection was successfull
if (result != SOCKET_ERROR)
{
LINFO("Connection established with server at ip: "<< _address);
LINFO("Connection established with server at ip: "<< _address);
//we're connected
_isConnected.store(true);
//we're connected
_isConnected.store(true);
//start sending messages
_sendThread = std::make_unique<std::thread>(&ParallelConnection::sendFunc, this);
//start sending messages
_sendThread = std::make_unique<std::thread>(&ParallelConnection::sendFunc, this);
//start listening for communication
_listenThread = std::make_unique<std::thread>(&ParallelConnection::listenCommunication, this);
//start listening for communication
_listenThread = std::make_unique<std::thread>(&ParallelConnection::listenCommunication, this);
//we no longer need to try to establish connection
_tryConnect.store(false);
//we no longer need to try to establish connection
_tryConnect.store(false);
_sendBufferMutex.lock();
_sendBuffer.clear();
_sendBufferMutex.unlock();
_sendBufferMutex.lock();
_sendBuffer.clear();
_sendBufferMutex.unlock();
//send authentication
sendAuthentication();
} else {
LINFO("Connection attempt failed.");
}
#ifdef WIN32
//on windows: try to connect once per second
std::this_thread::sleep_for(std::chrono::seconds(1));
#else
if(!_isConnected.load()){
//on unix disconnect and display error message if we're not connected
LERROR("Failed to establish a connection with server "<< _address << " on port " << _port<<", terminating connection.");
//signal disconnect
signalDisconnect();
//stop loop
break;
}
#endif
//send authentication
sendAuthentication();
} else {
LINFO("Connection attempt failed.");
signalDisconnect();
}
//cleanup
@@ -366,8 +361,10 @@ void ParallelConnection::establishConnection(addrinfo *info){
}
void ParallelConnection::sendAuthentication() {
std::string name = _name.value();
//length of this nodes name
uint32_t nameLength = static_cast<uint32_t>(_name.length());
uint32_t nameLength = static_cast<uint32_t>(name.length());
//total size of the buffer: (passcode + namelength + name)
size_t size = 2 * sizeof(uint32_t) + nameLength;
@@ -376,14 +373,16 @@ void ParallelConnection::sendAuthentication() {
std::vector<char> buffer;
buffer.reserve(size);
uint32_t passCode = hash(_password.value());
//write passcode to buffer
buffer.insert(buffer.end(), reinterpret_cast<char*>(&_passCode), reinterpret_cast<char*>(&_passCode) + sizeof(uint32_t));
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*>(&nameLength), reinterpret_cast<char*>(&nameLength) + sizeof(uint32_t));
//write this node's name to buffer
buffer.insert(buffer.end(), _name.begin(), _name.end());
buffer.insert(buffer.end(), name.begin(), name.end());
//send buffer
queueOutMessage(Message(MessageType::Authentication, buffer));
@@ -505,6 +504,10 @@ double ParallelConnection::calculateBufferedKeyframeTime(double originalTime) {
}
_latencyDiffs.push_back(latencyDiff);
return originalTime + timeDiff + latencyDiff + _bufferTime;
}
double ParallelConnection::latencyStandardDeviation() const {
double accumulatedLatencyDiffSquared = 0;
double accumulatedLatencyDiff = 0;
for (double diff : _latencyDiffs) {
@@ -516,16 +519,14 @@ double ParallelConnection::calculateBufferedKeyframeTime(double originalTime) {
// V(X) = E(x^2) - E(x)^2
double latencyVariance = expectedLatencyDiffSquared - expectedLatencyDiff*expectedLatencyDiff;
double latencyStandardDeviation = std::sqrt(latencyVariance);
double frametime = OsEng.windowWrapper().averageDeltaTime();
double latencyCompensation = std::max(expectedLatencyDiff + 2 * latencyStandardDeviation, latencyDiff);
return originalTime + timeDiff + nBroadcastIntervalsBuffer * BroadcastIntervalMilliseconds / 1000 + latencyCompensation + nFrametimesBuffer * frametime;
return std::sqrt(latencyVariance);
}
double ParallelConnection::timeTolerance() const {
return _timeTolerance;
}
void ParallelConnection::dataMessageReceived(const std::vector<char>& messageContent) {
//the type of data message received
@@ -534,26 +535,26 @@ void ParallelConnection::dataMessageReceived(const std::vector<char>& messageCon
switch(static_cast<datamessagestructures::Type>(type)) {
case datamessagestructures::Type::CameraData: {
datamessagestructures::CameraKeyframe kf(buffer);
kf._timestamp = calculateBufferedKeyframeTime(kf._timestamp);
OsEng.interactionHandler().removeKeyframesAfter(kf._timestamp);
OsEng.interactionHandler().addKeyframe(kf);
break;
}
case datamessagestructures::Type::TimeData: {
datamessagestructures::TimeKeyframe kf(buffer);
kf._timestamp = calculateBufferedKeyframeTime(kf._timestamp);
OsEng.timeManager().removeKeyframesAfter(kf._timestamp);
OsEng.timeManager().addKeyframe(kf);
break;
}
case datamessagestructures::Type::ScriptData: {
datamessagestructures::ScriptMessage sm;
sm.deserialize(buffer);
OsEng.scriptEngine().queueScript(sm._script, scripting::ScriptEngine::RemoteScripting::No);
OsEng.scriptEngine().queueScript(sm._script, scripting::ScriptEngine::RemoteScripting::No);
break;
}
default:{
@@ -691,17 +692,6 @@ void ParallelConnection::connectionStatusMessageReceived(const std::vector<char>
setStatus(status);
if (status == Status::Host) { // assigned as host
_broadcastThread = std::make_unique<std::thread>(&ParallelConnection::broadcast, this);
} else { // assigned as client
// delete broadcasting thread
// (the thread is allowed to terminate once the status is set to non-host.)
if (_broadcastThread != nullptr) {
_broadcastThread->join();
_broadcastThread = nullptr;
}
}
OsEng.interactionHandler().clearKeyframes();
OsEng.timeManager().clearKeyframes();
@@ -879,22 +869,22 @@ int ParallelConnection::receiveData(_SOCKET & socket, std::vector<char> &buffer,
return result;
}
void ParallelConnection::setPort(const std::string &port){
_port = port;
void ParallelConnection::setPort(std::string port){
_port = std::move(port);
}
void ParallelConnection::setAddress(const std::string &address){
_address = address;
void ParallelConnection::setAddress(std::string address){
_address = std::move(address);
}
void ParallelConnection::setName(const std::string& name){
_name = name;
void ParallelConnection::setName(std::string name){
_name = std::move(name);
}
void ParallelConnection::requestHostship(const std::string &password){
void ParallelConnection::requestHostship(){
std::vector<char> buffer;
uint32_t passcode = hash(password);
uint32_t passcode = hash(_hostPassword);
buffer.insert(buffer.end(), reinterpret_cast<char*>(&passcode), reinterpret_cast<char*>(&passcode) + sizeof(uint32_t));
queueOutMessage(Message(MessageType::HostshipRequest, buffer));
}
@@ -904,8 +894,12 @@ void ParallelConnection::resignHostship() {
queueOutMessage(Message(MessageType::HostshipResignation, buffer));
}
void ParallelConnection::setPassword(const std::string& pwd){
_passCode = hash(pwd);
void ParallelConnection::setPassword(std::string pwd){
_password = std::move(pwd);
}
void ParallelConnection::setHostPassword(std::string pwd) {
_hostPassword = std::move(pwd);
}
bool ParallelConnection::initNetworkAPI(){
@@ -934,11 +928,11 @@ bool ParallelConnection::initNetworkAPI(){
return true;
}
void ParallelConnection::sendScript(const std::string& script) {
void ParallelConnection::sendScript(std::string script) {
if (!isHost()) return;
datamessagestructures::ScriptMessage sm;
sm._script = script;
sm._script = std::move(script);
std::vector<char> buffer;
sm.serialize(buffer);
@@ -946,6 +940,13 @@ void ParallelConnection::sendScript(const std::string& script) {
queueOutDataMessage(DataMessage(datamessagestructures::Type::ScriptData, buffer));
}
void ParallelConnection::resetTimeOffset() {
OsEng.interactionHandler().clearKeyframes();
OsEng.timeManager().clearKeyframes();
std::lock_guard<std::mutex> latencyLock(_latencyMutex);
_latencyDiffs.clear();
}
void ParallelConnection::preSynchronization(){
std::unique_lock<std::mutex> unqlock(_receiveBufferMutex);
@@ -959,12 +960,23 @@ void ParallelConnection::preSynchronization(){
if (Time::ref().timeJumped()) {
_timeJumped = true;
}
double now = OsEng.runTime();
if (_lastCameraKeyframeTimestamp + _cameraKeyframeInterval < now) {
sendCameraKeyframe();
_lastCameraKeyframeTimestamp = now;
}
if (_lastTimeKeyframeTimestamp + _timeKeyframeInterval < now) {
sendTimeKeyframe();
_lastTimeKeyframeTimestamp = now;
}
}
}
void ParallelConnection::setStatus(Status status) {
if (_status != status) {
_status = status;
_timeJumped = true;
_connectionEvent->publish("statusChanged");
}
}
@@ -1000,26 +1012,40 @@ const std::string& ParallelConnection::hostName() {
}
void ParallelConnection::sendCameraKeyframe() {
//create a keyframe with current position and orientation of camera
datamessagestructures::CameraKeyframe kf;
kf._position = OsEng.interactionHandler().camera()->positionVec3();
kf._rotation = OsEng.interactionHandler().camera()->rotationQuaternion();
SceneGraphNode* focusNode = OsEng.interactionHandler().focusNode();
if (!focusNode) {
return;
}
//timestamp as current runtime of OpenSpace instance
// Create a keyframe with current position and orientation of camera
datamessagestructures::CameraKeyframe kf;
kf._position = OsEng.interactionHandler().focusNodeToCameraVector();
kf._followNodeRotation = OsEng.interactionHandler().interactionMode()->followingNodeRotation();
if (kf._followNodeRotation) {
kf._position = glm::inverse(focusNode->worldRotationMatrix()) * kf._position;
kf._rotation = OsEng.interactionHandler().focusNodeToCameraRotation();
} else {
kf._rotation = OsEng.interactionHandler().camera()->rotationQuaternion();
}
kf._focusNode = focusNode->name();
// Timestamp as current runtime of OpenSpace instance
kf._timestamp = OsEng.runTime();
//create a buffer for the keyframe
// Create a buffer for the keyframe
std::vector<char> buffer;
//fill the keyframe buffer
// Fill the keyframe buffer
kf.serialize(buffer);
//send message
// Send message
queueOutDataMessage(DataMessage(datamessagestructures::Type::CameraData, buffer));
}
void ParallelConnection::sendTimeKeyframe() {
//create a keyframe with current position and orientation of camera
// Create a keyframe with current position and orientation of camera
datamessagestructures::TimeKeyframe kf;
kf._dt = Time::ref().deltaTime();
@@ -1027,33 +1053,20 @@ void ParallelConnection::sendTimeKeyframe() {
kf._requiresTimeJump = _timeJumped;
kf._time = Time::ref().j2000Seconds();
//timestamp as current runtime of OpenSpace instance
// Timestamp as current runtime of OpenSpace instance
kf._timestamp = OsEng.runTime();
//create a buffer for the keyframe
// Create a buffer for the keyframe
std::vector<char> buffer;
//fill the keyframe buffer
// Fill the keyframe buffer
kf.serialize(buffer);
//send message
// Send message
queueOutDataMessage(DataMessage(datamessagestructures::Type::TimeData, buffer));
_timeJumped = false;
}
void ParallelConnection::broadcast(){
_timeJumped = true;
//while we're still connected and we're the host
while (_isConnected && isHost()) {
sendCameraKeyframe();
sendTimeKeyframe();
//100 ms sleep - send keyframes 10 times per second
std::this_thread::sleep_for(std::chrono::milliseconds(static_cast<int>(BroadcastIntervalMilliseconds)));
}
}
uint32_t ParallelConnection::hash(const std::string &val) {
uint32_t hashVal = 0, i;
size_t len = val.length();
@@ -1080,30 +1093,6 @@ scripting::LuaLibrary ParallelConnection::luaLibrary() {
return {
"parallel",
{
{
"setPort",
&luascriptfunctions::setPort,
"number",
"Set the port for the parallel connection"
},
{
"setAddress",
&luascriptfunctions::setAddress,
"string",
"Set the address for the parallel connection"
},
{
"setPassword",
&luascriptfunctions::setPassword,
"string",
"Set the password for the parallel connection"
},
{
"setDisplayName",
&luascriptfunctions::setDisplayName,
"string",
"Set your display name for the parallel connection"
},
{
"connect",
&luascriptfunctions::connect,
@@ -1119,7 +1108,7 @@ scripting::LuaLibrary ParallelConnection::luaLibrary() {
{
"requestHostship",
&luascriptfunctions::requestHostship,
"string",
"",
"Request to be the host for this session"
},
{

View File

@@ -26,109 +26,10 @@ namespace openspace {
namespace luascriptfunctions {
/**
* \ingroup LuaScripts
* setPort():
* Set the port for parallel connection
*/
int setPort(lua_State* L) {
bool isFunction = (lua_isfunction(L, -1) != 0);
if (isFunction) {
// If the top of the stack is a function, it is ourself
const char* msg = lua_pushfstring(L, "method called without argument");
return luaL_error(L, "bad argument (%s)", msg);
}
bool isNumber = (lua_isnumber(L, -1) != 0);
if (isNumber) {
int value = static_cast<int>(lua_tonumber(L, -1));
std::string port = std::to_string(value);
if (OsEng.windowWrapper().isMaster()) {
OsEng.parallelConnection().setPort(port);
}
return 0;
}
else {
const char* msg = lua_pushfstring(L, "%s expected, got %s",
lua_typename(L, LUA_TNUMBER), luaL_typename(L, -1));
return luaL_error(L, "bad argument #%d (%s)", 1, msg);
}
}
int setAddress(lua_State* L) {
bool isFunction = (lua_isfunction(L, -1) != 0);
if (isFunction) {
// If the top of the stack is a function, it is ourself
const char* msg = lua_pushfstring(L, "method called without argument");
return luaL_error(L, "bad argument (%s)", msg);
}
int type = lua_type(L, -1);
if (type == LUA_TSTRING) {
std::string address = luaL_checkstring(L, -1);
if (OsEng.windowWrapper().isMaster()) {
OsEng.parallelConnection().setAddress(address);
}
return 0;
}
else {
const char* msg = lua_pushfstring(L, "%s expected, got %s",
lua_typename(L, LUA_TSTRING), luaL_typename(L, -1));
return luaL_error(L, "bad argument #%d (%s)", 1, msg);
}
}
int setPassword(lua_State* L) {
bool isFunction = (lua_isfunction(L, -1) != 0);
if (isFunction) {
// If the top of the stack is a function, it is ourself
const char* msg = lua_pushfstring(L, "method called without argument");
return luaL_error(L, "bad argument (%s)", msg);
}
int type = lua_type(L, -1);
if (type == LUA_TSTRING) {
std::string pwd = luaL_checkstring(L, -1);
if (OsEng.windowWrapper().isMaster()) {
OsEng.parallelConnection().setPassword(pwd);
}
return 0;
}
else {
const char* msg = lua_pushfstring(L, "%s expected, got %s",
lua_typename(L, LUA_TSTRING), luaL_typename(L, -1));
return luaL_error(L, "bad argument #%d (%s)", 1, msg);
}
}
int setDisplayName(lua_State* L) {
bool isFunction = (lua_isfunction(L, -1) != 0);
if (isFunction) {
// If the top of the stack is a function, it is ourself
const char* msg = lua_pushfstring(L, "method called without argument");
return luaL_error(L, "bad argument (%s)", msg);
}
int type = lua_type(L, -1);
if (type == LUA_TSTRING) {
std::string name = luaL_checkstring(L, -1);
if (OsEng.windowWrapper().isMaster()) {
OsEng.parallelConnection().setName(name);
}
return 0;
}
else {
const char* msg = lua_pushfstring(L, "%s expected, got %s",
lua_typename(L, LUA_TSTRING), luaL_typename(L, -1));
return luaL_error(L, "bad argument #%d (%s)", 1, msg);
}
}
int connect(lua_State* L) {
int nArguments = lua_gettop(L);
if (nArguments != 0) {
return luaL_error(L, "Expected %i arguments, got %i", 0, nArguments);
}
SCRIPT_CHECK_ARGUMENTS("connect", L, 0, nArguments);
if (OsEng.windowWrapper().isMaster()) {
OsEng.parallelConnection().clientConnect();
}
@@ -137,9 +38,8 @@ int connect(lua_State* L) {
int disconnect(lua_State* L) {
int nArguments = lua_gettop(L);
if (nArguments != 0) {
return luaL_error(L, "Expected %i arguments, got %i", 0, nArguments);
}
SCRIPT_CHECK_ARGUMENTS("disconnect", L, 0, nArguments);
if (OsEng.windowWrapper().isMaster()) {
OsEng.parallelConnection().signalDisconnect();
}
@@ -147,33 +47,19 @@ int disconnect(lua_State* L) {
}
int requestHostship(lua_State* L) {
bool isFunction = (lua_isfunction(L, -1) != 0);
if (isFunction) {
// If the top of the stack is a function, it is ourself
const char* msg = lua_pushfstring(L, "method called without argument");
return luaL_error(L, "bad argument (%s)", msg);
}
int type = lua_type(L, -1);
if (type == LUA_TSTRING) {
std::string pwd = luaL_checkstring(L, -1);
if (OsEng.windowWrapper().isMaster()) {
OsEng.parallelConnection().requestHostship(pwd);
}
return 0;
}
else {
const char* msg = lua_pushfstring(L, "%s expected, got %s",
lua_typename(L, LUA_TSTRING), luaL_typename(L, -1));
return luaL_error(L, "bad argument #%d (%s)", 1, msg);
int nArguments = lua_gettop(L);
SCRIPT_CHECK_ARGUMENTS("requestHostship", L, 0, nArguments);
if (OsEng.windowWrapper().isMaster()) {
OsEng.parallelConnection().requestHostship();
}
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);
}
SCRIPT_CHECK_ARGUMENTS("resignHostship", L, 0, nArguments);
if (OsEng.windowWrapper().isMaster()) {
OsEng.parallelConnection().resignHostship();
}

View File

@@ -324,5 +324,13 @@ const std::string& PropertyOwner::name() const {
return _name;
}
std::vector<std::string> PropertyOwner::tags() const {
return _tags;
}
void PropertyOwner::addTag(std::string tag) {
_tags.push_back(std::move(tag));
}
} // namespace properties
} // namespace openspace

View File

@@ -41,6 +41,7 @@ namespace {
const char* keyStart = "StartTime";
const char* keyEnd = "EndTime";
const char* KeyType = "Type";
const char* KeyTag = "Tag";
}
namespace openspace {
@@ -112,6 +113,21 @@ Renderable::Renderable(const ghoul::Dictionary& dictionary)
dictionary.getValue(keyStart, _startTime);
dictionary.getValue(keyEnd, _endTime);
if (dictionary.hasKeyAndValue<std::string>(KeyTag)) {
std::string tagName = dictionary.value<std::string>(KeyTag);
if (!tagName.empty())
addTag(std::move(tagName));
} else if (dictionary.hasKeyAndValue<ghoul::Dictionary>(KeyTag)) {
ghoul::Dictionary tagNames = dictionary.value<ghoul::Dictionary>(KeyTag);
std::vector<std::string> keys = tagNames.keys();
std::string tagName;
for (const std::string& key : keys) {
tagName = tagNames.value<std::string>(key);
if (!tagName.empty())
addTag(std::move(tagName));
}
}
if (_startTime != "" && _endTime != "") {
_hasTimeInterval = true;
}

View File

@@ -108,6 +108,7 @@ RenderEngine::RenderEngine()
, _takeScreenshot("takeScreenshot", "Take Screenshot")
, _showFrameNumber("showFrameNumber", "Show Frame Number", false)
, _disableMasterRendering("disableMasterRendering", "Disable Master Rendering", false)
, _disableSceneOnMaster("disableSceneOnMaster", "Disable Scene on Master", false)
, _shouldTakeScreenshot(false)
, _renderer(nullptr)
, _rendererImplementation(RendererImplementation::Invalid)
@@ -165,6 +166,7 @@ RenderEngine::RenderEngine()
addProperty(_showFrameNumber);
addProperty(_disableMasterRendering);
addProperty(_disableSceneOnMaster);
}
void RenderEngine::setRendererFromString(const std::string& renderingMethod) {
@@ -211,6 +213,12 @@ void RenderEngine::initialize() {
);
}
if (confManager.hasKey(ConfigurationManager::KeyDisableSceneOnMaster)) {
_disableSceneOnMaster = confManager.value<bool>(
ConfigurationManager::KeyDisableSceneOnMaster
);
}
_raycasterManager = std::make_unique<RaycasterManager>();
_nAaSamples = OsEng.windowWrapper().currentNumberOfAaSamples();
@@ -383,12 +391,20 @@ void RenderEngine::updateFade() {
void RenderEngine::render(const glm::mat4& viewMatrix, const glm::mat4& projectionMatrix) {
void RenderEngine::render(const glm::mat4& sceneMatrix, const glm::mat4& viewMatrix,
const glm::mat4& projectionMatrix)
{
LTRACE("RenderEngine::render(begin)");
_camera->sgctInternal.setViewMatrix(viewMatrix);
WindowWrapper& wrapper = OsEng.windowWrapper();
if (_disableSceneOnMaster && wrapper.isMaster()) {
_camera->sgctInternal.setViewMatrix(viewMatrix);
}
else {
_camera->sgctInternal.setViewMatrix(viewMatrix * sceneMatrix);
}
_camera->sgctInternal.setProjectionMatrix(projectionMatrix);
WindowWrapper& wrapper = OsEng.windowWrapper();
if (!(wrapper.isMaster() && _disableMasterRendering) && !wrapper.isGuiWindow()) {
_renderer->render(_globalBlackOutFactor, _performanceManager != nullptr);

View File

@@ -47,7 +47,7 @@ namespace {
const char* KeyScale = "Scale";
const char* KeyDepth = "Depth";
const char* KeyAlpha = "Alpha";
const char* KeyTag = "Tag";
const float PlaneDepth = -2.f;
}
@@ -146,6 +146,21 @@ ScreenSpaceRenderable::ScreenSpaceRenderable(const ghoul::Dictionary& dictionary
dictionary.getValue(KeyDepth, _depth);
dictionary.getValue(KeyAlpha, _alpha);
if (dictionary.hasKeyAndValue<std::string>(KeyTag)) {
std::string tagName = dictionary.value<std::string>(KeyTag);
if (!tagName.empty())
addTag(std::move(tagName));
} else if (dictionary.hasKeyAndValue<ghoul::Dictionary>(KeyTag)) {
ghoul::Dictionary tagNames = dictionary.value<ghoul::Dictionary>(KeyTag);
std::vector<std::string> keys = tagNames.keys();
std::string tagName;
for (const std::string& key : keys) {
tagName = tagNames.value<std::string>(key);
if (!tagName.empty())
addTag(std::move(tagName));
}
}
// Setting spherical/euclidean onchange handler
_useFlatScreen.onChange([this](){
if (_useFlatScreen) {

View File

@@ -435,26 +435,38 @@ scripting::LuaLibrary Scene::luaLibrary() {
"setPropertyValue",
&luascriptfunctions::property_setValue,
"string, *",
"Sets all properties identified by the URI (with potential wildcards) in "
"the first argument. The second argument can be any type, but it has to "
"match the type that the property (or properties) expect."
"Sets all property(s) identified by the URI (with potential wildcards) "
"in the first argument. The second argument can be any type, but it has "
"to match the type that the property (or properties) expect. If the "
"first term (separated by '.') in the uri is bracketed with { }, then "
"this term is treated as a group tag name, and the function will "
"search through all property owners to find those that are tagged with "
"this group name, and set their property values accordingly."
},
{
"setPropertyValueRegex",
&luascriptfunctions::property_setValueRegex,
"string, *",
"Sets all properties that pass the regular expression in the first "
"argument. The second argument can be any type, but it has to match the "
"type of the properties that matched the regular expression. The regular "
"expression has to be of the ECMAScript grammar."
"Sets all property(s) that pass the regular expression in the first "
"argument. The second argument can be any type, but it has to match "
"the type of the properties that matched the regular expression. "
"The regular expression has to be of the ECMAScript grammar. If the "
"first term (separated by '.') in the uri is bracketed with { }, then "
"this term is treated as a group tag name, and the function will search "
"through all property owners to find those that are tagged with this "
"group name, and set their property values accordingly."
},
{
"setPropertyValueSingle",
&luascriptfunctions::property_setValueSingle,
"string, *",
"Sets a property identified by the URI in "
"the first argument. The second argument can be any type, but it has to "
"match the type that the property expects.",
"Sets all property(s) identified by the URI in the first argument to the "
"value passed in the second argument. The type of the second argument is "
"arbitrary, but it must agree with the type the denoted Property expects."
" If the first term (separated by '.') in the uri is bracketed with { }, "
" then this term is treated as a group tag name, and the function will "
"search through all property owners to find those that are tagged with "
"this group name, and set their property values accordingly."
},
{
"getPropertyValue",

View File

@@ -28,17 +28,67 @@ namespace openspace {
namespace {
void applyRegularExpression(lua_State* L, std::regex regex, std::vector<properties::Property*> properties, int type) {
void executePropertySet(properties::Property* prop, lua_State* L) {
prop->setLuaValue(L);
//ensure properties are synced over parallel connection
std::string value;
prop->getStringValue(value);
/*OsEng.parallelConnection().scriptMessage(
prop->fullyQualifiedIdentifier(),
value
);*/
}
template <class T>
properties::PropertyOwner* findPropertyOwnerWithMatchingGroupTag(T* prop,
const std::string& tagToMatch)
{
properties::PropertyOwner* tagMatchOwner = nullptr;
properties::PropertyOwner* owner = prop->owner();
if (owner) {
std::vector<std::string> tags = owner->tags();
for (std::string& currTag : tags) {
if (tagToMatch.compare(currTag) == 0) {
tagMatchOwner = owner;
break;
}
}
//Call recursively until we find an owner with matching tag or the top of the
// ownership list
if (tagMatchOwner == nullptr)
tagMatchOwner = findPropertyOwnerWithMatchingGroupTag(owner, tagToMatch);
}
return tagMatchOwner;
}
void applyRegularExpression(lua_State* L, std::regex regex,
std::vector<properties::Property*> properties, int type,
std::string groupName = "")
{
using ghoul::lua::errorLocation;
using ghoul::lua::luaTypeToString;
bool isGroupMode = !groupName.empty();
for (properties::Property* prop : properties) {
// Check the regular expression for all properties
std::string id = prop->fullyQualifiedIdentifier();
if (std::regex_match(id, regex)) {
// If the fully qualified id matches the regular expression, we queue the
// value change if the types agree
if (isGroupMode) {
properties::PropertyOwner* matchingTaggedOwner =
findPropertyOwnerWithMatchingGroupTag(
prop,
groupName
);
if (!matchingTaggedOwner) {
continue;
}
}
if (type != prop->typeLua()) {
LERRORC("property_setValue",
errorLocation(L) << "Property '" <<
@@ -46,55 +96,50 @@ void applyRegularExpression(lua_State* L, std::regex regex, std::vector<properti
"' does not accept input of type '" << luaTypeToString(type) <<
"'. Requested type: '" << luaTypeToString(prop->typeLua()) << "'"
);
} else {
executePropertySet(prop, L);
}
else {
prop->setLuaValue(L);
//ensure properties are synced over parallel connection
std::string value;
prop->getStringValue(value);
/* OsEng.parallelConnection().scriptMessage(
prop->fullyQualifiedIdentifier(),
value
);*/
}
}
}
}
//Checks to see if URI contains a group tag (with { } around the first term). If so,
// returns true and sets groupName with the tag
bool doesUriContainGroupTag(const std::string& command, std::string& groupName) {
std::string name = command.substr(0, command.find_first_of("."));
if (name.front() == '{' && name.back() == '}') {
groupName = name.substr(1, name.length() - 2);
return true;
} else {
return false;
}
}
std::string replaceUriWithGroupName(std::string uri, std::string ownerName) {
size_t pos = uri.find_first_of(".");
return ownerName + "." + uri.substr(pos);
}
std::string extractUriWithoutGroupName(std::string uri) {
size_t pos = uri.find_first_of(".");
return uri.substr(pos);
}
}
namespace luascriptfunctions {
/**
* \ingroup LuaScripts
* setPropertyValueSingle(string, *):
* Sets the property identified by the URI in the first argument to the value passed to
* the second argument. The type of the second argument is arbitrary, but it must agree
* with the type the denoted Property expects
*/
int property_setValueSingle(lua_State* L) {
int setPropertyCall_single(properties::Property* prop, std::string uri, lua_State* L,
const int type)
{
using ghoul::lua::errorLocation;
using ghoul::lua::luaTypeToString;
int nArguments = lua_gettop(L);
SCRIPT_CHECK_ARGUMENTS("property_setValueSingle", L, 2, nArguments);
std::string uri = luaL_checkstring(L, -2);
const int type = lua_type(L, -1);
properties::Property* prop = property(uri);
if (!prop) {
LERRORC("property_setValue", errorLocation(L) << "Property with URI '" << uri << "' was not found");
return 0;
}
if (type != prop->typeLua()) {
LERRORC("property_setValue", errorLocation(L) << "Property '" << uri <<
"' does not accept input of type '" << luaTypeToString(type) <<
"'. Requested type: '" << luaTypeToString(prop->typeLua()) << "'");
return 0;
}
else {
prop->setLuaValue(L);
@@ -107,12 +152,116 @@ int property_setValueSingle(lua_State* L) {
return 0;
}
/**
* \ingroup LuaScripts
* setPropertyValueSingle(string, *):
* Sets all property(s) identified by the URI in the first argument to the value passed
* in the second argument. The type of the second argument is arbitrary, but it must
* agree with the type the denoted Property expects.
* If the first term (separated by '.') in the uri is bracketed with { }, then this
* term is treated as a group tag name, and the function will search through all
* property owners to find those that are tagged with this group name, and set their
* property values accordingly.
*/
int property_setValueSingle(lua_State* L) {
using ghoul::lua::errorLocation;
using ghoul::lua::luaTypeToString;
int nArguments = lua_gettop(L);
SCRIPT_CHECK_ARGUMENTS("property_setValueSingle", L, 2, nArguments);
std::string uri = luaL_checkstring(L, -2);
const int type = lua_type(L, -1);
std::string tagToMatch;
if (doesUriContainGroupTag(uri, tagToMatch)) {
std::string pathRemainderToMatch = extractUriWithoutGroupName(uri);
for (properties::Property* prop : allProperties()) {
std::string propFullId = prop->fullyQualifiedIdentifier();
//Look for a match in the uri with the group name (first term) removed
int propMatchLength = propFullId.length() - pathRemainderToMatch.length();
if (propMatchLength >= 0) {
std::string thisPropMatchId = propFullId.substr(propMatchLength);
//If remainder of uri matches (with group name removed),
if (pathRemainderToMatch.compare(thisPropMatchId) == 0) {
properties::PropertyOwner* matchingTaggedOwner
= findPropertyOwnerWithMatchingGroupTag(prop, tagToMatch);
if (matchingTaggedOwner) {
setPropertyCall_single(prop, uri, L, type);
}
}
}
}
} else {
properties::Property* prop = property(uri);
if (!prop) {
LERRORC("property_setValue", errorLocation(L) << "Property with URI '"
<< uri << "' was not found");
return 0;
}
setPropertyCall_single(prop, uri, L, type);
}
return 0;
}
/**
* \ingroup LuaScripts
* setPropertyValue(string, *):
* Sets all property(s) identified by the URI (with potential wildcards) in the first
* argument. The second argument can be any type, but it has to match the type that the
* property (or properties) expect.
* If the first term (separated by '.') in the uri is bracketed with { }, then this
* term is treated as a group tag name, and the function will search through all
* property owners to find those that are tagged with this group name, and set their
* property values accordingly.
*/
int property_setValue(lua_State* L) {
using ghoul::lua::errorLocation;
using ghoul::lua::luaTypeToString;
int nArguments = lua_gettop(L);
SCRIPT_CHECK_ARGUMENTS("property_setGroup", L, 2, nArguments);
std::string regex = luaL_checkstring(L, -2);
std::string groupName;
// Replace all wildcards * with the correct regex (.*)
size_t startPos = regex.find("*");
while (startPos != std::string::npos) {
regex.replace(startPos, 1, "(.*)");
startPos += 4;
startPos = regex.find("*", startPos);
}
if (doesUriContainGroupTag(regex, groupName)) {
std::string pathRemainderToMatch = extractUriWithoutGroupName(regex);
//Remove group name from start of regex and replace with '.*'
regex = replaceUriWithGroupName(regex, ".*");
}
applyRegularExpression(
L,
std::regex(regex/*, std::regex_constants::optimize*/),
allProperties(),
lua_type(L, -1),
groupName
);
return 0;
}
/**
* \ingroup LuaScripts
* setPropertyValueRegex(string, *):
* Sets all properties that pass the regular expression in the first argument. The second
* Sets all property(s) that pass the regular expression in the first argument. The second
* argument can be any type, but it has to match the type of the properties that matched
* the regular expression. The regular expression has to be of the ECMAScript grammar.
* If the first term (separated by '.') in the uri is bracketed with { }, then this
* term is treated as a group tag name, and the function will search through all
* property owners to find those that are tagged with this group name, and set their
* property values accordingly.
*/
int property_setValueRegex(lua_State* L) {
using ghoul::lua::errorLocation;
@@ -120,63 +269,32 @@ int property_setValueRegex(lua_State* L) {
int nArguments = lua_gettop(L);
SCRIPT_CHECK_ARGUMENTS("property_setValueRegex<", L, 2, nArguments);
std::string regex = luaL_checkstring(L, -2);
std::string groupName;
if (doesUriContainGroupTag(regex, groupName)) {
std::string pathRemainderToMatch = extractUriWithoutGroupName(regex);
//Remove group name from start of regex and replace with '.*'
regex = replaceUriWithGroupName(regex, ".*");
}
try {
applyRegularExpression(
L,
std::regex(regex, std::regex_constants::optimize),
allProperties(),
lua_type(L, -1)
lua_type(L, -1),
groupName
);
}
catch (const std::regex_error&) {
LERRORC(
"property_setValueRegex",
"Malformed regular expression: '" << regex << "'"
);
catch (const std::regex_error& e) {
LERRORC("property_setValueRegex", "Malformed regular expression: '"
<< regex << "'");
}
return 0;
}
/**
* \ingroup LuaScripts
* setPropertyValue(string, *):
* Sets all properties identified by the URI (with potential wildcards) in the first
* argument. The second argument can be any type, but it has to match the type that the
* property (or properties) expect.
*/
int property_setValue(lua_State* L) {
using ghoul::lua::errorLocation;
using ghoul::lua::luaTypeToString;
int nArguments = lua_gettop(L);
SCRIPT_CHECK_ARGUMENTS("property_setValue", L, 2, nArguments);
std::string regex = luaL_checkstring(L, -2);
// Replace all wildcards * with the correct regex (.*)
size_t startPos = regex.find("*");
while (startPos != std::string::npos) {
regex.replace(startPos, 1, "(.*)");
startPos += 4;
startPos = regex.find("*", startPos);
}
applyRegularExpression(
L,
std::regex(regex/*, std::regex_constants::optimize*/),
allProperties(),
lua_type(L, -1)
);
return 0;
}
/**
* \ingroup LuaScripts
* getPropertyValue(string):

View File

@@ -64,6 +64,7 @@ const std::string SceneGraphNode::RootNodeName = "Root";
const std::string SceneGraphNode::KeyName = "Name";
const std::string SceneGraphNode::KeyParentName = "Parent";
const std::string SceneGraphNode::KeyDependencies = "Dependencies";
const std::string SceneGraphNode::KeyTag = "Tag";
std::unique_ptr<SceneGraphNode> SceneGraphNode::createFromDictionary(const ghoul::Dictionary& dictionary){
openspace::documentation::testSpecificationAndThrow(
@@ -135,6 +136,25 @@ std::unique_ptr<SceneGraphNode> SceneGraphNode::createFromDictionary(const ghoul
LDEBUG("Successfully created scale for '" << result->name() << "'");
}
if (dictionary.hasKey(KeyTag)) {
if (dictionary.hasKeyAndValue<std::string>(KeyTag)) {
std::string tagName = dictionary.value<std::string>(KeyTag);
if (!tagName.empty()) {
result->addTag(std::move(tagName));
}
} else if (dictionary.hasKeyAndValue<ghoul::Dictionary>(KeyTag)) {
ghoul::Dictionary tagNames = dictionary.value<ghoul::Dictionary>(KeyTag);
std::vector<std::string> keys = tagNames.keys();
std::string tagName;
for (const std::string& key : keys) {
tagName = tagNames.value<std::string>(key);
if (!tagName.empty()) {
result->addTag(std::move(tagName));
}
}
}
}
LDEBUG("Successfully created SceneGraphNode '"
<< result->name() << "'");
return std::move(result);
@@ -263,7 +283,17 @@ void SceneGraphNode::update(const UpdateData& data) {
newUpdateData.modelTransform.translation = worldPosition();
newUpdateData.modelTransform.rotation = worldRotationMatrix();
newUpdateData.modelTransform .scale = worldScale();
newUpdateData.modelTransform.scale = worldScale();
glm::dmat4 translation =
glm::translate(glm::dmat4(1.0), newUpdateData.modelTransform.translation);
glm::dmat4 rotation = glm::dmat4(newUpdateData.modelTransform.rotation);
glm::dmat4 scaling =
glm::scale(glm::dmat4(1.0), glm::dvec3(newUpdateData.modelTransform.scale,
newUpdateData.modelTransform.scale, newUpdateData.modelTransform.scale));
_modelTransformCached = translation * rotation * scaling;
_inverseModelTransformCached = glm::inverse(_modelTransformCached);
if (_renderable && _renderable->isReady()) {
if (data.doPerformanceMeasurement) {
@@ -476,6 +506,14 @@ const glm::dmat3& SceneGraphNode::worldRotationMatrix() const
return _worldRotationCached;
}
glm::dmat4 SceneGraphNode::modelTransform() const {
return _modelTransformCached;
}
glm::dmat4 SceneGraphNode::inverseModelTransform() const {
return _inverseModelTransformCached;
}
double SceneGraphNode::worldScale() const
{
return _worldScaleCached;

View File

@@ -25,10 +25,7 @@
#include <openspace/util/timemanager.h>
#include <openspace/engine/openspaceengine.h>
#include <openspace/util/time.h>
namespace {
double SecondsOffTolerance = 0.1;
}
#include <openspace/network/parallelconnection.h>
namespace openspace {
@@ -96,8 +93,10 @@ void TimeManager::consumeKeyframes(double dt) {
return;
}
const double secondsOffTolerance = OsEng.parallelConnection().timeTolerance();
double predictedTime = time.j2000Seconds() + time.deltaTime() * (next._timestamp - now);
bool withinTolerance = std::abs(predictedTime - next._time) < std::abs(next._dt * SecondsOffTolerance);
bool withinTolerance = std::abs(predictedTime - next._time) < std::abs(next._dt * secondsOffTolerance);
if (next._dt == time.deltaTime() && withinTolerance) {
Time::ref().advanceTime(dt);
@@ -121,6 +120,7 @@ void TimeManager::consumeKeyframes(double dt) {
time.setDeltaTime(y1Prime);
time.setTime(y1, false);
// std::cout << "Correcting time to " << y1 << ", dt=" << y1Prime << "." << std::endl;
}
}
@@ -133,6 +133,13 @@ void TimeManager::addKeyframe(const TimeKeyframe& kf) {
_keyframes.insert(iter, kf);
}
void TimeManager::removeKeyframesAfter(double timestamp) {
datamessagestructures::TimeKeyframe kf;
kf._timestamp = timestamp;
auto iter = std::upper_bound(_keyframes.begin(), _keyframes.end(), kf, &TimeManager::compareKeyframeTimes);
_keyframes.erase(iter, _keyframes.end());
}
void TimeManager::removeKeyframesBefore(double timestamp) {
datamessagestructures::TimeKeyframe kf;
@@ -145,8 +152,11 @@ void TimeManager::clearKeyframes() {
_keyframes.clear();
}
bool TimeManager::compareKeyframeTimes(const TimeKeyframe& a, const TimeKeyframe& b)
{
const std::deque<datamessagestructures::TimeKeyframe>& TimeManager::keyframes() const {
return _keyframes;
}
bool TimeManager::compareKeyframeTimes(const TimeKeyframe& a, const TimeKeyframe& b) {
return a._timestamp < b._timestamp;
}

View File

@@ -80,6 +80,9 @@ TEST_F(DocumentationTest, Constructor) {
doc.entries.emplace_back("NotInListInt", new IntNotInListVerifier({ 0, 1 }));
doc.entries.emplace_back("NotInListString", new StringNotInListVerifier({ "", "a" }));
doc.entries.emplace_back("StringListVerifier", new StringListVerifier);
doc.entries.emplace_back("IntListVerifier", new IntListVerifier);
// Range Verifiers
doc.entries.emplace_back("InListDouble", new DoubleInRangeVerifier({ 0.0, 1.0 }));
doc.entries.emplace_back("InListInt", new IntInRangeVerifier({ 0, 1 }));
@@ -393,6 +396,63 @@ TEST_F(DocumentationTest, StringListVerifierType) {
EXPECT_EQ(TestResult::Offense::Reason::MissingKey, negativeRes.offenses[0].reason);
}
TEST_F(DocumentationTest, IntListVerifierType) {
using namespace openspace::documentation;
using namespace std::string_literals;
Documentation doc {
{ { "IntList", new IntListVerifier } }
};
ghoul::Dictionary positive {
{
"IntList",
ghoul::Dictionary{
{ "1", 1 },
{ "2", 2 },
{ "3", 3 }
}
}
};
TestResult positiveRes = testSpecification(doc, positive);
EXPECT_TRUE(positiveRes.success);
EXPECT_EQ(0, positiveRes.offenses.size());
ghoul::Dictionary negative{
{ "IntList", 0 }
};
TestResult negativeRes = testSpecification(doc, negative);
EXPECT_FALSE(negativeRes.success);
ASSERT_EQ(1, negativeRes.offenses.size());
EXPECT_EQ("IntList", negativeRes.offenses[0].offender);
EXPECT_EQ(TestResult::Offense::Reason::WrongType, negativeRes.offenses[0].reason);
ghoul::Dictionary negative2 {
{
"IntList",
ghoul::Dictionary{
{ "1", "a"s },
{ "2", 1 },
{ "3", 2 }
}
}
};
negativeRes = testSpecification(doc, negative2);
EXPECT_FALSE(negativeRes.success);
ASSERT_EQ(1, negativeRes.offenses.size());
EXPECT_EQ("IntList.1", negativeRes.offenses[0].offender);
EXPECT_EQ(TestResult::Offense::Reason::WrongType, negativeRes.offenses[0].reason);
ghoul::Dictionary negativeExist {
{ "IntList2", ghoul::Dictionary{} }
};
negativeRes = testSpecification(doc, negativeExist);
EXPECT_FALSE(negativeRes.success);
ASSERT_EQ(1, negativeRes.offenses.size());
EXPECT_EQ("IntList", negativeRes.offenses[0].offender);
EXPECT_EQ(TestResult::Offense::Reason::MissingKey, negativeRes.offenses[0].reason);
}
TEST_F(DocumentationTest, MixedVerifiers) {
using namespace openspace::documentation;
using namespace std::string_literals;