Merge branch 'develop' of github.com:OpenSpace/OpenSpace into feature/parallelconnection

Conflicts:
	include/openspace/engine/openspaceengine.h
	src/engine/openspaceengine.cpp
	src/interaction/interactionhandler.cpp
	src/network/parallelconnection.cpp
	src/scripting/scriptengine.cpp
This commit is contained in:
Emil Axelsson
2016-09-22 19:33:05 +02:00
311 changed files with 12363 additions and 4144 deletions

View File

@@ -24,13 +24,19 @@
set(OPENSPACE_SOURCE
${OPENSPACE_BASE_DIR}/src/openspace.cpp
${OPENSPACE_BASE_DIR}/src/documentation/core_registration.cpp
${OPENSPACE_BASE_DIR}/src/documentation/documentation.cpp
${OPENSPACE_BASE_DIR}/src/documentation/documentationengine.cpp
${OPENSPACE_BASE_DIR}/src/documentation/verifier.cpp
${OPENSPACE_BASE_DIR}/src/engine/configurationmanager.cpp
${OPENSPACE_BASE_DIR}/src/engine/configurationmanager_doc.inl
${OPENSPACE_BASE_DIR}/src/engine/downloadmanager.cpp
${OPENSPACE_BASE_DIR}/src/engine/logfactory.cpp
${OPENSPACE_BASE_DIR}/src/engine/moduleengine.cpp
${OPENSPACE_BASE_DIR}/src/engine/moduleengine_lua.inl
${OPENSPACE_BASE_DIR}/src/engine/openspaceengine.cpp
${OPENSPACE_BASE_DIR}/src/engine/settingsengine.cpp
${OPENSPACE_BASE_DIR}/src/engine/syncengine.cpp
${OPENSPACE_BASE_DIR}/src/engine/wrapper/sgctwindowwrapper.cpp
${OPENSPACE_BASE_DIR}/src/engine/wrapper/windowwrapper.cpp
${OPENSPACE_BASE_DIR}/src/interaction/controller.cpp
@@ -77,11 +83,14 @@ set(OPENSPACE_SOURCE
${OPENSPACE_BASE_DIR}/src/scene/rotation.cpp
${OPENSPACE_BASE_DIR}/src/scene/scale.cpp
${OPENSPACE_BASE_DIR}/src/scene/scene.cpp
${OPENSPACE_BASE_DIR}/src/scene/scene_doc.inl
${OPENSPACE_BASE_DIR}/src/scene/scene_lua.inl
${OPENSPACE_BASE_DIR}/src/scene/scenegraph.cpp
${OPENSPACE_BASE_DIR}/src/scene/scenegraphnode.cpp
${OPENSPACE_BASE_DIR}/src/scene/scenegraphnode_doc.inl
${OPENSPACE_BASE_DIR}/src/scripting/lualibrary.cpp
${OPENSPACE_BASE_DIR}/src/scripting/scriptengine.cpp
${OPENSPACE_BASE_DIR}/src/scripting/scriptscheduler.cpp
${OPENSPACE_BASE_DIR}/src/scripting/scriptengine_lua.inl
${OPENSPACE_BASE_DIR}/src/util/blockplaneintersectiongeometry.cpp
${OPENSPACE_BASE_DIR}/src/util/boxgeometry.cpp
@@ -97,6 +106,7 @@ set(OPENSPACE_SOURCE
${OPENSPACE_BASE_DIR}/src/util/spicemanager.cpp
${OPENSPACE_BASE_DIR}/src/util/spicemanager_lua.inl
${OPENSPACE_BASE_DIR}/src/util/syncbuffer.cpp
${OPENSPACE_BASE_DIR}/src/util/syncdata.cpp
${OPENSPACE_BASE_DIR}/src/util/histogram.cpp
${OPENSPACE_BASE_DIR}/src/util/time.cpp
${OPENSPACE_BASE_DIR}/src/util/timemanager.cpp
@@ -106,12 +116,18 @@ set(OPENSPACE_SOURCE
set(OPENSPACE_HEADER
${OPENSPACE_BASE_DIR}/include/openspace/openspace.h
${OPENSPACE_BASE_DIR}/include/openspace/documentation/core_registration.h
${OPENSPACE_BASE_DIR}/include/openspace/documentation/documentation.h
${OPENSPACE_BASE_DIR}/include/openspace/documentation/documentationengine.h
${OPENSPACE_BASE_DIR}/include/openspace/documentation/verifier.h
${OPENSPACE_BASE_DIR}/include/openspace/documentation/verifier.inl
${OPENSPACE_BASE_DIR}/include/openspace/engine/configurationmanager.h
${OPENSPACE_BASE_DIR}/include/openspace/engine/downloadmanager.h
${OPENSPACE_BASE_DIR}/include/openspace/engine/logfactory.h
${OPENSPACE_BASE_DIR}/include/openspace/engine/moduleengine.h
${OPENSPACE_BASE_DIR}/include/openspace/engine/openspaceengine.h
${OPENSPACE_BASE_DIR}/include/openspace/engine/settingsengine.h
${OPENSPACE_BASE_DIR}/include/openspace/engine/syncengine.h
${OPENSPACE_BASE_DIR}/include/openspace/engine/wrapper/sgctwindowwrapper.h
${OPENSPACE_BASE_DIR}/include/openspace/engine/wrapper/windowwrapper.h
${OPENSPACE_BASE_DIR}/include/openspace/interaction/controller.h
@@ -170,6 +186,7 @@ set(OPENSPACE_HEADER
${OPENSPACE_BASE_DIR}/include/openspace/scripting/lualibrary.h
${OPENSPACE_BASE_DIR}/include/openspace/scripting/script_helper.h
${OPENSPACE_BASE_DIR}/include/openspace/scripting/scriptengine.h
${OPENSPACE_BASE_DIR}/include/openspace/scripting/scriptscheduler.h
${OPENSPACE_BASE_DIR}/include/openspace/util/blockplaneintersectiongeometry.h
${OPENSPACE_BASE_DIR}/include/openspace/util/boxgeometry.h
${OPENSPACE_BASE_DIR}/include/openspace/util/camera.h
@@ -185,6 +202,7 @@ set(OPENSPACE_HEADER
${OPENSPACE_BASE_DIR}/include/openspace/util/screenlog.h
${OPENSPACE_BASE_DIR}/include/openspace/util/spicemanager.h
${OPENSPACE_BASE_DIR}/include/openspace/util/syncbuffer.h
${OPENSPACE_BASE_DIR}/include/openspace/util/syncdata.h
${OPENSPACE_BASE_DIR}/include/openspace/util/time.h
${OPENSPACE_BASE_DIR}/include/openspace/util/timemanager.h
${OPENSPACE_BASE_DIR}/include/openspace/util/updatestructures.h

View File

@@ -0,0 +1,53 @@
/*****************************************************************************************
* *
* 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 <openspace/documentation/core_registration.h>
#include <openspace/documentation/documentationengine.h>
#include <openspace/engine/configurationmanager.h>
#include <openspace/scene/scene.h>
#include <openspace/scene/scenegraphnode.h>
#include <openspace/rendering/renderable.h>
#include <openspace/rendering/screenspacerenderable.h>
#include <openspace/scene/ephemeris.h>
#include <openspace/scene/rotation.h>
#include <openspace/scene/scale.h>
namespace openspace {
namespace documentation {
void registerCoreClasses(documentation::DocumentationEngine& engine) {
engine.addDocumentation(ConfigurationManager::Documentation());
engine.addDocumentation(Ephemeris::Documentation());
engine.addDocumentation(Renderable::Documentation());
engine.addDocumentation(Rotation::Documentation());
engine.addDocumentation(Scale::Documentation());
engine.addDocumentation(Scene::Documentation());
engine.addDocumentation(SceneGraphNode::Documentation());
engine.addDocumentation(ScreenSpaceRenderable::Documentation());
}
} // namespace documentation
} // namespace openspace

View File

@@ -0,0 +1,199 @@
/*****************************************************************************************
* *
* 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 <openspace/documentation/documentation.h>
#include <openspace/documentation/verifier.h>
#include <set>
namespace {
// Structure used to make offenses unique
struct OffenseCompare {
using Offense = openspace::documentation::TestResult::Offense;
bool operator()(const Offense& lhs, const Offense& rhs) const
{
if (lhs.offender != rhs.offender) {
return lhs.offender < rhs.offender;
}
else {
return std::underlying_type_t<Offense::Reason>(lhs.reason) <
std::underlying_type_t<Offense::Reason>(rhs.reason);
}
}
};
} // namespace
// Unfortunately, the standard library does not contain a no-op for the to_string method
// so we have to include one ourselves
namespace std {
std::string to_string(std::string value) {
return value;
}
std::string to_string(openspace::documentation::TestResult::Offense::Reason reason) {
switch (reason) {
case openspace::documentation::TestResult::Offense::Reason::ExtraKey:
return "Extra key";
case openspace::documentation::TestResult::Offense::Reason::MissingKey:
return "Missing key";
case openspace::documentation::TestResult::Offense::Reason::UnknownIdentifier:
return "Unknown identifier";
case openspace::documentation::TestResult::Offense::Reason::Verification:
return "Verification failed";
case openspace::documentation::TestResult::Offense::Reason::WrongType:
return "Wrong type";
}
}
} // namespace std
namespace openspace {
namespace documentation {
const std::string DocumentationEntry::Wildcard = "*";
SpecificationError::SpecificationError(TestResult res, std::string component)
: ghoul::RuntimeError("Error in specification", std::move(component))
, result(std::move(res))
{
ghoul_assert(!result.success, "Result's success must be false");
}
DocumentationEntry::DocumentationEntry(std::string k, std::shared_ptr<Verifier> v,
std::string doc, Optional opt)
: key(std::move(k))
, verifier(std::move(v))
, documentation(std::move(doc))
, optional(opt)
{
ghoul_assert(!key.empty(), "Key must not be empty");
ghoul_assert(verifier, "Verifier must not be nullptr");
}
DocumentationEntry::DocumentationEntry(std::string key, Verifier* v, std::string doc,
Optional optional)
: DocumentationEntry(std::move(key), std::shared_ptr<Verifier>(v), std::move(doc),
optional)
{}
Documentation::Documentation(std::string n, std::string id, DocumentationEntries entries,
Exhaustive exh)
: name(std::move(n))
, id(std::move(id))
, entries(std::move(entries))
, exhaustive(std::move(exh))
{}
Documentation::Documentation(std::string n, DocumentationEntries entries, Exhaustive exh)
: Documentation(n, "", entries, exh)
{}
Documentation::Documentation(DocumentationEntries entries, Exhaustive exh)
: Documentation("", "", entries, exh)
{}
TestResult testSpecification(const Documentation& d, const ghoul::Dictionary& dict) {
TestResult result;
result.success = true;
auto applyVerifier = [dict, &result](Verifier& verifier, const std::string& key) {
TestResult res = verifier(dict, key);
if (!res.success) {
result.success = false;
result.offenses.insert(
result.offenses.end(),
res.offenses.begin(),
res.offenses.end()
);
}
};
for (const auto& p : d.entries) {
if (p.key == DocumentationEntry::Wildcard) {
for (const std::string& key : dict.keys()) {
applyVerifier(*(p.verifier), key);
}
}
else {
if (p.optional && !dict.hasKey(p.key)) {
// If the key is optional and it doesn't exist, we don't need to check it
// if the key exists, it has to be correct, however
continue;
}
applyVerifier(*(p.verifier), p.key);
}
}
if (d.exhaustive) {
// If the documentation is exhaustive, we have to check if there are extra values
// in the table that are not covered by the Documentation
for (const std::string& key : dict.keys()) {
auto it = std::find_if(
d.entries.begin(),
d.entries.end(),
[&key](const DocumentationEntry& entry) {
if (entry.key == DocumentationEntry::Wildcard) {
return true;
}
else {
return entry.key == key;
}
}
);
if (it == d.entries.end()) {
result.success = false;
result.offenses.push_back(
{ key, TestResult::Offense::Reason::ExtraKey }
);
}
}
}
// Remove duplicate offenders that might occur if multiple rules apply to a single
// key and more than one of these rules are broken
std::set<TestResult::Offense, OffenseCompare> uniqueOffenders(
result.offenses.begin(), result.offenses.end()
);
result.offenses = std::vector<TestResult::Offense>(
uniqueOffenders.begin(), uniqueOffenders.end()
);
return result;
}
void testSpecificationAndThrow(const Documentation& doc, const ghoul::Dictionary& dict,
std::string component)
{
// Perform testing against the documentation/specification
TestResult testResult = testSpecification(doc, dict);
if (!testResult.success) {
throw SpecificationError(std::move(testResult), std::move(component));
}
}
} // namespace documentation
} // namespace openspace

View File

@@ -0,0 +1,281 @@
/*****************************************************************************************
* *
* 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 <openspace/documentation/documentationengine.h>
#include <openspace/documentation/verifier.h>
#include <ghoul/misc/assert.h>
#include <fstream>
#include <fmt/format.h>
namespace openspace {
namespace documentation {
DocumentationEngine::DuplicateDocumentationException::DuplicateDocumentationException(
Documentation documentation)
: ghoul::RuntimeError(fmt::format(
"Duplicate Documentation with name '{}' and id '{}'",
documentation.name,
documentation.id
))
, documentation(std::move(documentation))
{}
DocumentationEngine& DocumentationEngine::ref() {
static DocumentationEngine engine;
return engine;
}
std::string generateTextDocumentation(const Documentation& d, int& indentLevel) {
using namespace std::string_literals;
auto indentMessage = [&indentLevel](std::string prefix, std::string msg) {
if (msg.empty()) {
return ""s;
}
else {
return std::string(indentLevel, '\t') + prefix + ": " + msg + '\n';
}
};
std::string result;
result += indentMessage("Name", d.name);
if (!d.name.empty()) {
++indentLevel;
}
for (const auto& p : d.entries) {
result += indentMessage("Key", (p.key == "*") ? p.key : "\"" + p.key + "\"");
result += indentMessage("Optional", (p.optional ? "true" : "false"));
result += indentMessage("Type", p.verifier->type());
TableVerifier* tv = dynamic_cast<TableVerifier*>(p.verifier.get());
if (tv) {
// We have a TableVerifier, so we need to recurse
++indentLevel;
result += generateTextDocumentation({ "", "", tv->documentations }, indentLevel);
result = result.substr(0, result.size() - 2);
--indentLevel;
}
else {
result += indentMessage("Restrictions", p.verifier->documentation());
}
result += indentMessage("Documentation", p.documentation);
result += "\n\n";
}
if (!d.name.empty()) {
--indentLevel;
}
return result;
}
std::string generateJsonDocumentation(const Documentation& d) {
std::stringstream result;
result << "{";
result << "\"name\": \"" << d.name << "\",";
result << "\"entries\": [";
for (const auto& p : d.entries) {
result << "{";
result << "\"key\": \"" << p.key << "\",";
result << "\"optional\": \"" << (p.optional ? "true" : "false") << "\",";
result << "\"type\": \"" << p.verifier->type() << "\",";
TableVerifier* tv = dynamic_cast<TableVerifier*>(p.verifier.get());
if (tv) {
std::string json = generateJsonDocumentation({ "", "", tv->documentations });
// We have a TableVerifier, so we need to recurse
result << "\"restrictions\": " << json << ",";
}
else {
result << "\"restrictions\": \"" << p.verifier->documentation() << "\",";
}
result << "},";
}
result << ']';
result << "}";
return result.str();
}
std::string generateHtmlDocumentation(const Documentation& d) {
std::stringstream html;
html << "\t<tr>\n"
<< "\t\t<td colspan=6>" << d.name << "<a name=\"" << d.id << "\"></a></td>\n";
for (const auto& p : d.entries) {
html << "\t<tr>\n"
<< "\t\t<td></td>\n"
<< "\t\t<td>" << p.key << "</td>\n"
<< "\t\t<td>" << (p.optional ? "Optional" : "Required") << "</td>\n"
<< "\t\t<td>" << p.verifier->type() << "</td>\n";
TableVerifier* tv = dynamic_cast<TableVerifier*>(p.verifier.get());
ReferencingVerifier* rv = dynamic_cast<ReferencingVerifier*>(p.verifier.get());
// We have to check ReferencingVerifier first as a ReferencingVerifier is also a
// TableVerifier
if (rv) {
std::vector<Documentation> documentations = DocEng.documentations();
auto it = std::find_if(
documentations.begin(),
documentations.end(),
[rv](const Documentation& doc) { return doc.id == rv->identifier; }
);
html << "\t\t<td>"
<< "\t\t\tReferencing: "
<< "<a href=\"#" << rv->identifier << "\">" << it->name << "</a>"
<< "\t\t</td>";
}
else if (tv) {
// We have a TableVerifier, so we need to recurse
html << "<td><table cellpadding=3 cellspacing=0 border=1>\n"
<< "\t<thead>\n"
<< "\t\t<tr>\n"
<< "\t\t\t<th></th>\n"
<< "\t\t\t<th>Key</th>\n"
<< "\t\t\t<th>Optional</th>\n"
<< "\t\t\t<th>Type</th>\n"
<< "\t\t\t<th>Restrictions</th>\n"
<< "\t\t\t<th>Documentation</th>\n"
<< "\t\t</tr>\n"
<< "\t</thead>\n"
<< "\t<tbody>\n"
<< generateHtmlDocumentation({ "", "", tv->documentations })
<< "\t</tbody>\n"
<< "</table>\n"
<< "</td>\n";
}
else {
html << "\t\t<td>" << p.verifier->documentation() << "</td>\n";
}
html << "\t\t<td>" << p.documentation << "</td>\n"
<< "\t</tr>\n";
}
return html.str();
}
void DocumentationEngine::writeDocumentation(const std::string& f, const std::string& t) {
if (t == "text") {
std::ofstream file;
file.exceptions(~std::ofstream::goodbit);
file.open(f);
for (const Documentation& d : _documentations) {
int indent = 0;
file << documentation::generateTextDocumentation(d, indent) << "\n\n";
}
}
else if (t == "html") {
std::ofstream file;
file.exceptions(~std::ofstream::goodbit);
file.open(f);
#ifdef JSON
std::stringstream json;
json << "[";
for (const Documentation& d : _documentations) {
json << generateJsonDocumentation(d);
json << ",";
}
json << "]";
std::string jsonText = json.str();
#else
std::stringstream html;
html << "<html>\n"
<< "\t<head>\n"
<< "\t\t<title>Documentation</title>\n"
<< "\t</head>\n"
<< "<body>\n";
html << "<table cellpadding=3 cellspacing=0 border=1>\n"
<< "\t<caption>Documentation</caption>\n\n"
<< "\t<thead>\n"
<< "\t\t<tr>\n"
<< "\t\t\t<th rowspan=2>Name</th>\n"
<< "\t\t</tr>\n"
<< "\t\t<tr>\n"
<< "\t\t\t<th>Key</th>\n"
<< "\t\t\t<th>Optional</th>\n"
<< "\t\t\t<th>Type</th>\n"
<< "\t\t\t<th>Restrictions</th>\n"
<< "\t\t\t<th>Documentation</th>\n"
<< "\t\t</tr>\n"
<< "\t</thead>\n"
<< "\t<tbody>\n";
for (const Documentation& d : _documentations) {
html << generateHtmlDocumentation(d);
html << "\t<tr><td style=\"line-height: 50px;\" colspan=6></br></td></tr>\n";
}
html << "\t</tbody>\n"
<< "</table>\n";
html << "</body>\n";
html << "</html>\n";
file << html.str();
#endif
}
}
void DocumentationEngine::addDocumentation(Documentation doc) {
if (doc.id.empty()) {
_documentations.push_back(std::move(doc));
}
else {
auto it = std::find_if(
_documentations.begin(),
_documentations.end(),
[doc](const Documentation& d) { return doc.id == d.id; }
);
if (it != _documentations.end()) {
throw DuplicateDocumentationException(std::move(doc));
}
else {
_documentations.push_back(std::move(doc));
}
}
}
std::vector<Documentation> DocumentationEngine::documentations() const {
return _documentations;
}
} // namespace documentation
} // namespace openspace

View File

@@ -0,0 +1,273 @@
/*****************************************************************************************
* *
* 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 <openspace/documentation/verifier.h>
#include <openspace/documentation/documentationengine.h>
namespace openspace {
namespace documentation {
// The explicit template instantiations for many of the commonly used template values
// This cuts down on the compilation time by only compiling these once
template struct Vector2Verifier<bool>;
template struct Vector2Verifier<int>;
template struct Vector2Verifier<double>;
template struct Vector3Verifier<bool>;
template struct Vector3Verifier<int>;
template struct Vector3Verifier<double>;
template struct Vector4Verifier<bool>;
template struct Vector4Verifier<int>;
template struct Vector4Verifier<double>;
template struct LessVerifier<IntVerifier>;
template struct LessVerifier<DoubleVerifier>;
template struct LessEqualVerifier<IntVerifier>;
template struct LessEqualVerifier<DoubleVerifier>;
template struct GreaterVerifier<IntVerifier>;
template struct GreaterVerifier<DoubleVerifier>;
template struct GreaterEqualVerifier<IntVerifier>;
template struct GreaterEqualVerifier<DoubleVerifier>;
template struct EqualVerifier<BoolVerifier>;
template struct EqualVerifier<IntVerifier>;
template struct EqualVerifier<DoubleVerifier>;
template struct EqualVerifier<StringVerifier>;
template struct UnequalVerifier<BoolVerifier>;
template struct UnequalVerifier<IntVerifier>;
template struct UnequalVerifier<DoubleVerifier>;
template struct UnequalVerifier<StringVerifier>;
template struct InListVerifier<BoolVerifier>;
template struct InListVerifier<IntVerifier>;
template struct InListVerifier<DoubleVerifier>;
template struct InListVerifier<StringVerifier>;
template struct NotInListVerifier<BoolVerifier>;
template struct NotInListVerifier<IntVerifier>;
template struct NotInListVerifier<DoubleVerifier>;
template struct NotInListVerifier<StringVerifier>;
template struct InRangeVerifier<IntVerifier>;
template struct InRangeVerifier<DoubleVerifier>;
template struct NotInRangeVerifier<IntVerifier>;
template struct NotInRangeVerifier<DoubleVerifier>;
template struct AnnotationVerifier<BoolVerifier>;
template struct AnnotationVerifier<IntVerifier>;
template struct AnnotationVerifier<DoubleVerifier>;
template struct AnnotationVerifier<StringVerifier>;
template struct AnnotationVerifier<TableVerifier>;
std::string BoolVerifier::type() const {
return "Boolean";
}
std::string DoubleVerifier::type() const {
return "Double";
}
TestResult IntVerifier::operator()(const ghoul::Dictionary & dict,
const std::string & key) const {
if (dict.hasKeyAndValue<int>(key)) {
// We we have a key and the value is int, we are done
return{ true, {} };
}
else {
if (dict.hasKey(key)) {
if (dict.hasValue<double>(key)) {
// If we have a double value, we need to check if it is integer
double value = dict.value<double>(key);
double intPart;
bool isInt = modf(value, &intPart) == 0.0;
if (isInt) {
return{ true,{} };
}
else {
return{ false, { { key, TestResult::Offense::Reason::WrongType } } };
}
}
else {
// If we don't have a double value, we cannot have an int value
return{ false, { { key, TestResult::Offense::Reason::WrongType } } };
}
}
else {
return{ false, { {key, TestResult::Offense::Reason::MissingKey }} };
}
}
}
std::string IntVerifier::type() const {
return "Integer";
}
std::string StringVerifier::type() const {
return "String";
}
TableVerifier::TableVerifier(std::vector<DocumentationEntry> d, Exhaustive exhaustive)
: documentations(std::move(d))
, exhaustive(std::move(exhaustive)) {}
TestResult TableVerifier::operator()(const ghoul::Dictionary& dict,
const std::string& key) const {
if (dict.hasKeyAndValue<Type>(key)) {
ghoul::Dictionary d = dict.value<ghoul::Dictionary>(key);
TestResult res = testSpecification({ "", documentations, exhaustive }, d);
for (TestResult::Offense& s : res.offenses) {
s.offender = key + "." + s.offender;
}
return res;
}
else {
if (dict.hasKey(key)) {
return{ false, { { key, TestResult::Offense::Reason::WrongType } } };
}
else {
return{ false, { { key, TestResult::Offense::Reason::MissingKey } } };
}
}
}
std::string TableVerifier::type() const {
return "Table";
}
ReferencingVerifier::ReferencingVerifier(std::string id)
: identifier(std::move(id))
{
ghoul_assert(!identifier.empty(), "identifier must not be empty");
}
TestResult ReferencingVerifier::operator()(const ghoul::Dictionary& dictionary,
const std::string& key) const
{
TestResult res = TableVerifier::operator()(dictionary, key);
if (res.success) {
std::vector<Documentation> documentations = DocEng.documentations();
auto it = std::find_if(
documentations.begin(),
documentations.end(),
[this](const Documentation& doc) { return doc.id == identifier; }
);
if (it == documentations.end()) {
return { false, { { key, TestResult::Offense::Reason::UnknownIdentifier } } };
}
else {
ghoul::Dictionary d = dictionary.value<ghoul::Dictionary>(key);
TestResult res = testSpecification(*it, d);
for (TestResult::Offense& s : res.offenses) {
s.offender = key + "." + s.offender;
}
return res;
}
}
else {
return res;
}
}
std::string ReferencingVerifier::documentation() const {
using namespace std::string_literals;
return "Referencing Documentation: '"s + identifier + "'";
}
AndVerifier::AndVerifier(Verifier* lhs, Verifier* rhs)
: lhs(lhs)
, rhs(rhs)
{
ghoul_assert(lhs, "lhs must not be nullptr");
ghoul_assert(rhs, "rhs must not be nullptr");
}
TestResult AndVerifier::operator()(const ghoul::Dictionary& dict,
const std::string& key) const
{
TestResult resLhs = lhs->operator()(dict, key);
TestResult resRhs = rhs->operator()(dict, key);
if (resLhs.success && resRhs.success) {
return { true, {} };
}
else {
return { false, { { key, TestResult::Offense::Reason::Verification } } };
}
}
std::string AndVerifier::type() const {
if (lhs->type() != rhs->type()) {
return lhs->type() + " and " + rhs->type();
}
else {
return lhs->type();
}
}
std::string AndVerifier::documentation() const {
return lhs->documentation() + " and " + rhs->documentation();
}
OrVerifier::OrVerifier(Verifier* lhs, Verifier* rhs)
: lhs(lhs)
, rhs(rhs)
{
ghoul_assert(lhs, "lhs must not be nullptr");
ghoul_assert(rhs, "rhs must not be nullptr");
}
TestResult OrVerifier::operator()(const ghoul::Dictionary& dict,
const std::string& key) const {
TestResult resA = lhs->operator()(dict, key);
TestResult resB = rhs->operator()(dict, key);
if (resA.success || resB.success) {
return { true, {} };
}
else {
return { false, { { key, TestResult::Offense::Reason::Verification } } };
}
}
std::string OrVerifier::type() const {
if (lhs->type() != rhs->type()) {
return lhs->type() + " or " + rhs->type();
}
else {
return lhs->type();
}
}
std::string OrVerifier::documentation() const {
return lhs->documentation() + " or " + rhs->documentation();
}
} // namespace documentation
} // namespace openspace

View File

@@ -32,6 +32,8 @@
using std::string;
#include "configurationmanager_doc.inl"
namespace {
const string _configurationFile = "openspace.cfg";
const string _keyBasePath = "BASE_PATH";
@@ -43,25 +45,32 @@ const string ConfigurationManager::KeyPaths = "Paths";
const string ConfigurationManager::KeyCache = "CACHE";
const string ConfigurationManager::KeyFonts = "Fonts";
const string ConfigurationManager::KeyConfigSgct = "SGCTConfig";
const string ConfigurationManager::KeyLuaDocumentationType = "LuaDocumentationFile.Type";
const string ConfigurationManager::KeyLuaDocumentationFile = "LuaDocumentationFile.File";
const string ConfigurationManager::KeyScriptLogType = "ScriptLogFile.Type";
const string ConfigurationManager::KeyScriptLogFile = "ScriptLogFile.File";
const string ConfigurationManager::KeyPropertyDocumentationType =
"PropertyDocumentationFile.Type";
const string ConfigurationManager::KeyPropertyDocumentationFile =
"PropertyDocumentationFile.File";
const string ConfigurationManager::KeyKeyboardShortcutsType = "KeyboardShortcuts.Type";
const string ConfigurationManager::KeyKeyboardShortcutsFile = "KeyboardShortcuts.File";
const string ConfigurationManager::PartType = "Type";
const string ConfigurationManager::PartFile = "File";
const string ConfigurationManager::KeyLuaDocumentation = "LuaDocumentation";
const string ConfigurationManager::KeyScriptLog = "ScriptLog";
const string ConfigurationManager::KeyPropertyDocumentation = "PropertyDocumentation";
const string ConfigurationManager::KeyKeyboardShortcuts = "KeyboardShortcuts";
const string ConfigurationManager::KeyDocumentation = "Documentation";
const string ConfigurationManager::KeyFactoryDocumentation = "FactoryDocumentation";
const string ConfigurationManager::KeyConfigScene = "Scene";
const string ConfigurationManager::KeyLogLevel = "Logging.LogLevel";
const string ConfigurationManager::KeyLogImmediateFlush = "Logging.ImmediateFlush";
const string ConfigurationManager::KeyLogs = "Logging.Logs";
const string ConfigurationManager::KeyLogging = "Logging";
const string ConfigurationManager::PartLogLevel = "LogLevel";
const string ConfigurationManager::PartImmediateFlush = "ImmediateFlush";
const string ConfigurationManager::PartLogs = "Logs";
const string ConfigurationManager::PartAppend = "Append";
const string ConfigurationManager::PartCapabilitiesVerbosity = "CapabilitiesVerbosity";
const string ConfigurationManager::KeyCapabilitiesVerbosity =
"Logging.CapabilitiesVerbosity";
KeyLogging + "." + PartCapabilitiesVerbosity;
const string ConfigurationManager::KeyShutdownCountdown = "ShutdownCountdown";
const string ConfigurationManager::KeyDisableMasterRendering = "DisableRenderingOnMaster";
const string ConfigurationManager::KeyDownloadRequestURL = "DownloadRequestURL";
const string ConfigurationManager::KeyRenderingMethod = "RenderingMethod";
string ConfigurationManager::findConfiguration(const string& filename) {
using ghoul::filesystem::Directory;
@@ -94,8 +103,9 @@ string ConfigurationManager::findConfiguration(const string& filename) {
void ConfigurationManager::loadFromFile(const string& filename) {
using ghoul::filesystem::FileSystem;
if (!FileSys.fileExists(filename))
if (!FileSys.fileExists(filename)) {
throw ghoul::FileNotFoundError(filename, "ConfigurationManager");
}
// ${BASE_PATH}
string basePathToken = FileSystem::TokenOpeningBraces + _keyBasePath
@@ -109,6 +119,13 @@ void ConfigurationManager::loadFromFile(const string& filename) {
// Loading the configuration file into ourselves
ghoul::lua::loadDictionaryFromFile(filename, *this);
// Perform testing against the documentation/specification
openspace::documentation::testSpecificationAndThrow(
ConfigurationManager::Documentation(),
*this,
"ConfigurationManager"
);
// Register all the paths
ghoul::Dictionary dictionary = value<ghoul::Dictionary>(KeyPaths);

View File

@@ -0,0 +1,333 @@
/*****************************************************************************************
* *
* 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 <openspace/documentation/verifier.h>
namespace openspace {
Documentation ConfigurationManager::Documentation() {
using namespace documentation;
return {
"OpenSpace Configuration",
{
{
ConfigurationManager::KeyConfigSgct,
new StringAnnotationVerifier("A valid SGCT configuration file"),
"The SGCT configuration file that determines the window and view frustum "
"settings that are being used when OpenSpace is started."
},
{
ConfigurationManager::KeyConfigScene,
new StringAnnotationVerifier(
"A valid scene file as described in the Scene documentation"),
"The scene description that is used to populate the application after "
"startup. The scene determines which objects are loaded, the startup "
"time and other scene-specific settings. More information is provided in "
"the Scene documentation."
},
{
ConfigurationManager::KeyPaths,
new TableVerifier({
{ "*", new StringVerifier }
}),
"A list of paths that are automatically registered with the file system. "
"If a key X is used in the table, it is then useable by referencing ${X} "
"in all other configuration files or scripts.",
Optional::Yes
},
{
ConfigurationManager::KeyFonts,
new TableVerifier({
{ "*", new StringVerifier, "Font paths loadable by FreeType" }
}),
"A list of all fonts that will automatically be loaded on startup. Each "
"key-value pair contained in the table will become the name and the file "
"for a font.",
Optional::Yes
},
{
ConfigurationManager::KeyLogging,
new TableVerifier({
{
ConfigurationManager::PartLogLevel,
new StringInListVerifier(
// List from logmanager.cpp::levelFromString
{"Debug", "Info", "Warning", "Error", "Fatal", "None" }
),
"The severity of log messages that will be displayed. Only "
"messages of the selected level or higher will be displayed. All "
"levels below will be silently discarded. The order of "
"severities is: Debug < Info < Warning < Error < Fatal < None.",
Optional::Yes
},
{
ConfigurationManager::PartImmediateFlush,
new BoolVerifier,
"Determines whether error messages will be displayed immediately "
"or if it is acceptable to have a short delay, but being more "
"performant. If the delay is allowed ('true'), messages might "
"get lost if the application crashes shortly after a message was "
"logged.",
Optional::Yes
},
{
ConfigurationManager::PartLogs,
new TableVerifier({
{
"*",
new TableVerifier({
{
ConfigurationManager::PartType,
new StringInListVerifier({
// List from logfactory.cpp::createLog
"text", "html"
}),
"The type of the new log to be generated."
},
{
ConfigurationManager::PartFile,
new StringVerifier,
"The filename to which the log will be written."
},
{
ConfigurationManager::PartAppend,
new BoolVerifier,
"Determines whether the file will be cleared at "
"startup or if the contents will be appended to "
"previous runs.",
Optional::Yes
}
}),
"Additional log files",
Optional::Yes
}
}),
"Per default, log messages are written to the console, the "
"onscreen text, and (if available) the Visual Studio output "
"window. This table can define other logging methods that will "
"be used additionally.",
Optional::Yes
},
{
ConfigurationManager::PartCapabilitiesVerbosity,
new StringInListVerifier(
// List from OpenspaceEngine::initialize
{ "None", "Minimal", "Default", "Full" }
),
"At startup, a list of system capabilities is created and logged."
"This value determines how verbose this listing should be.",
Optional::Yes
}
}),
"Configurations for the logging of messages that are generated "
"throughout the code and are useful for debugging potential errors or "
"other information.",
Optional::Yes
},
{
ConfigurationManager::KeyLuaDocumentation,
new TableVerifier({
{
ConfigurationManager::PartType,
new StringInListVerifier(
// List from ScriptEngine::writeDocumentation
{ "text", "html" }
),
"The type of documentation that will be written."
},
{
ConfigurationManager::PartFile,
new StringVerifier,
"The filename that will be created on startup containing the "
"documentation of available Lua functions. Any existing file "
"will be silently overwritten."
}
}),
"Descriptions of whether and where to create a documentation file that "
"describes the available Lua functions that can be executed in scene "
"files or per console.",
Optional::Yes
},
{
ConfigurationManager::KeyPropertyDocumentation,
new TableVerifier({
{
ConfigurationManager::PartType,
new StringInListVerifier(
// List taken from Scene::writePropertyDocumentation
{ "text", "html" }
),
"The type of property documentation file that is created."
},
{
ConfigurationManager::PartFile,
new StringVerifier,
"The file that will be created on startup containing a list of "
"all properties in the scene. Any existing file will be silently "
"overwritten."
}
}),
"Descriptions of whether and where to create a list of all properties "
"that were created in the current scene.",
Optional::Yes
},
{
ConfigurationManager::KeyScriptLog,
new TableVerifier({
{
ConfigurationManager::PartType,
new StringInListVerifier(
// List taken from ScriptEngine::writeLog
{ "text" }
),
"The type of logfile that will be created."
},
{
ConfigurationManager::PartFile,
new StringVerifier,
"The file that will be created on startup containing the log of "
"all Lua scripts that are executed. Any existing file (including "
"the results from previous runs) will be silently overwritten."
}
}),
"Contains a log of all Lua scripts that were executed in the last "
"session.",
Optional::Yes
},
{
ConfigurationManager::KeyKeyboardShortcuts,
new TableVerifier({
{
ConfigurationManager::PartType,
new StringInListVerifier(
// List from InteractionHandler::writeKeyboardDocumentation
{ "text", "html" }
),
"The type of keyboard binding documentation that should be "
"written."
},
{
ConfigurationManager::PartFile,
new StringVerifier,
"The file that will be created on startup containing the list of "
"all keyboard bindings with their respective Lua scripts. Any "
"previous file in this location will be silently overritten."
}
}),
"Contains the collection of all keyboard shortcuts that were collected "
"during startup. For each key, it mentions which scripts will be "
"executed in the current session.",
Optional::Yes
},
{
ConfigurationManager::KeyDocumentation,
new TableVerifier({
{
ConfigurationManager::PartType,
new StringInListVerifier(
// List from DocumentationEngine::writeDocumentation
{ "text", "html" }
),
"The type of documentation that should be written."
},
{
ConfigurationManager::PartFile,
new StringVerifier,
"The file that will be created on startup containing this "
"documentation. Any previous file in this location will be silently "
"overritten."
}
}),
"This defines the location and type of this documentation file.",
Optional::Yes
},
{
ConfigurationManager::KeyFactoryDocumentation,
new TableVerifier({
{
ConfigurationManager::PartType,
new StringInListVerifier(
// List from FactoryManager::writeDocumentation
{ "text", "html" }
),
"The type of documentation that should be written."
},
{
ConfigurationManager::PartFile,
new StringVerifier,
"The file that will be created on startup containing the factory "
"documentation. Any previous file in this location will be silently "
"overritten."
}
}),
"This defines the location and type of the factory documentation file, which "
"shows the different types of objects that can be created in the current "
"application configuration."
},
{
ConfigurationManager::KeyShutdownCountdown,
new DoubleGreaterEqualVerifier(0.0),
"The countdown that the application will wait between pressing ESC and "
"actually shutting down. If ESC is pressed again in this time, the "
"shutdown is aborted.",
Optional::Yes
},
{
ConfigurationManager::KeyDownloadRequestURL,
new OrVerifier(
new StringVerifier,
new TableVerifier({
{ "*", new StringVerifier }
})
),
"The URL from which files will be downloaded by the Launcher. This can "
"either be a single URL or a list of possible URLs from which the "
"Launcher can then choose.",
Optional::Yes
},
{
ConfigurationManager::KeyRenderingMethod,
new StringInListVerifier(
// List from RenderEngine::setRendererFromString
{ "Framebuffer", "ABuffer" }
),
"The renderer that is use after startup. The renderer 'ABuffer' requires "
"support for at least OpenGL 4.3",
Optional::Yes
},
{
ConfigurationManager::KeyDisableMasterRendering,
new BoolVerifier,
"Toggles whether the master in a multi-application setup should be rendering "
"or just managing the state of the network. This is desired in cases where "
"the master computer does not have the resources to render a scene.",
Optional::Yes
}
}
};
};
} // namespace openspace

View File

@@ -32,14 +32,14 @@
namespace {
const std::string keyType = "Type";
const std::string keyFilename = "FileName";
const std::string keyFilename = "File";
const std::string keyAppend = "Append";
const std::string keyTimeStamping = "TimeStamping";
const std::string keyDateStamping = "DateStamping";
const std::string keyCategoryStamping = "CategoryStamping";
const std::string keyLogLevelStamping = "LogLevelStamping";
const std::string valueHtmlLog = "HTML";
const std::string valueHtmlLog = "html";
const std::string valueTextLog = "Text";
}

View File

@@ -26,11 +26,14 @@
#include <openspace/openspace.h>
#include <openspace/documentation/core_registration.h>
#include <openspace/documentation/documentationengine.h>
#include <openspace/engine/configurationmanager.h>
#include <openspace/engine/downloadmanager.h>
#include <openspace/engine/logfactory.h>
#include <openspace/engine/moduleengine.h>
#include <openspace/engine/settingsengine.h>
#include <openspace/engine/syncengine.h>
#include <openspace/engine/wrapper/windowwrapper.h>
#include <openspace/interaction/interactionhandler.h>
#include <openspace/interaction/keyboardcontroller.h>
@@ -41,6 +44,7 @@
#include <openspace/rendering/renderable.h>
#include <openspace/rendering/renderengine.h>
#include <openspace/scripting/scriptengine.h>
#include <openspace/scripting/scriptscheduler.h>
#include <openspace/scene/ephemeris.h>
#include <openspace/scene/scene.h>
#include <openspace/util/factorymanager.h>
@@ -50,6 +54,7 @@
#include <openspace/util/syncbuffer.h>
#include <openspace/util/transformationmanager.h>
#include <ghoul/ghoul.h>
#include <ghoul/cmdparser/commandlineparser.h>
#include <ghoul/cmdparser/singlecommand.h>
@@ -65,6 +70,7 @@
#include <ghoul/misc/onscopeexit.h>
#include <fstream>
#include <queue>
#ifdef OPENSPACE_MODULE_ONSCREENGUI_ENABLED
#include <modules/onscreengui/include/gui.h>
@@ -107,6 +113,7 @@ namespace {
std::string configurationName;
std::string sgctConfigurationName;
std::string sceneName;
std::string cacheFolder;
} commandlineArgumentPlaceholders;
}
@@ -124,7 +131,9 @@ OpenSpaceEngine::OpenSpaceEngine(std::string programName,
, _interactionHandler(new interaction::InteractionHandler)
, _renderEngine(new RenderEngine)
, _scriptEngine(new scripting::ScriptEngine)
, _scriptScheduler(new scripting::ScriptScheduler)
, _networkEngine(new NetworkEngine)
, _syncEngine(std::make_unique<SyncEngine>(new SyncBuffer(4096)))
, _commandlineParser(new ghoul::cmdparser::CommandlineParser(
programName, ghoul::cmdparser::CommandlineParser::AllowUnknownCommands::Yes
))
@@ -141,7 +150,6 @@ OpenSpaceEngine::OpenSpaceEngine(std::string programName,
, _globalPropertyNamespace(new properties::PropertyOwner)
, _isMaster(false)
, _runTime(0.0)
, _syncBuffer(new SyncBuffer(4096))
, _isInShutdownMode(false)
, _shutdownCountdown(0.f)
, _shutdownWait(0.f)
@@ -150,12 +158,15 @@ OpenSpaceEngine::OpenSpaceEngine(std::string programName,
_interactionHandler->setPropertyOwner(_globalPropertyNamespace.get());
_globalPropertyNamespace->addPropertySubOwner(_interactionHandler.get());
_globalPropertyNamespace->addPropertySubOwner(_settingsEngine.get());
FactoryManager::initialize();
FactoryManager::ref().addFactory(
std::make_unique<ghoul::TemplateFactory<Renderable>>()
std::make_unique<ghoul::TemplateFactory<Renderable>>(),
"Renderable"
);
FactoryManager::ref().addFactory(
std::make_unique<ghoul::TemplateFactory<Ephemeris>>()
std::make_unique<ghoul::TemplateFactory<Ephemeris>>(),
"Ephemeris"
);
SpiceManager::initialize();
Time::initialize();
@@ -164,6 +175,8 @@ OpenSpaceEngine::OpenSpaceEngine(std::string programName,
}
OpenSpaceEngine::~OpenSpaceEngine() {
LINFO("_windowWrapper->isUsingSwapGroups(): " << _windowWrapper->isUsingSwapGroups());
LINFO("_windowWrapper->isSwapGroupMaster(): " << _windowWrapper->isSwapGroupMaster());
#ifdef OPENSPACE_MODULE_ONSCREENGUI_ENABLED
_gui->deinitializeGL();
#endif
@@ -178,6 +191,7 @@ OpenSpaceEngine::~OpenSpaceEngine() {
_renderEngine = nullptr;
_scriptEngine = nullptr;
_networkEngine = nullptr;
_syncEngine = nullptr;
_commandlineParser = nullptr;
_console = nullptr;
_moduleEngine = nullptr;
@@ -185,7 +199,6 @@ OpenSpaceEngine::~OpenSpaceEngine() {
#ifdef OPENSPACE_MODULE_ONSCREENGUI_ENABLED
_gui = nullptr;
#endif
_syncBuffer = nullptr;
}
OpenSpaceEngine& OpenSpaceEngine::ref() {
@@ -275,6 +288,14 @@ bool OpenSpaceEngine::create(int argc, char** argv,
return false;
}
if (!commandlineArgumentPlaceholders.cacheFolder.empty()) {
FileSys.registerPathToken(
"${CACHE}",
commandlineArgumentPlaceholders.cacheFolder,
ghoul::filesystem::FileSystem::Override::Yes
);
}
// Initialize the requested logs from the configuration file
_engine->configureLogging();
@@ -296,6 +317,15 @@ bool OpenSpaceEngine::create(int argc, char** argv,
// Register modules
_engine->_moduleEngine->initialize();
documentation::registerCoreClasses(DocEng);
// After registering the modules, the documentations for the available classes
// can be added as well
for (OpenSpaceModule* m : _engine->_moduleEngine->modules()) {
for (auto&& doc : m->documentations()) {
DocEng.addDocumentation(doc);
}
}
// Create the cachemanager
FileSys.createCacheManager(
absPath("${" + ConfigurationManager::KeyCache + "}"), CacheVersion
@@ -358,7 +388,9 @@ bool OpenSpaceEngine::initialize() {
using Verbosity = ghoul::systemcapabilities::SystemCapabilitiesComponent::Verbosity;
Verbosity verbosity = Verbosity::Default;
if (configurationManager().hasKeyAndValue<std::string>(ConfigurationManager::KeyCapabilitiesVerbosity)) {
if (configurationManager().hasKeyAndValue<std::string>(
ConfigurationManager::KeyCapabilitiesVerbosity)) {
std::map<std::string, Verbosity> verbosityMap = {
{ "None", Verbosity::None },
{ "Minimal", Verbosity::Minimal },
@@ -390,6 +422,7 @@ bool OpenSpaceEngine::initialize() {
_scriptEngine->addLibrary(gui::GUI::luaLibrary());
_scriptEngine->addLibrary(network::ParallelConnection::luaLibrary());
_scriptEngine->addLibrary(ModuleEngine::luaLibrary());
_scriptEngine->addLibrary(ScriptScheduler::luaLibrary());
#ifdef OPENSPACE_MODULE_ISWA_ENABLED
_scriptEngine->addLibrary(IswaManager::luaLibrary());
@@ -399,18 +432,54 @@ bool OpenSpaceEngine::initialize() {
scriptEngine().initialize();
// If a LuaDocumentationFile was specified, generate it now
const bool hasType = configurationManager().hasKey(ConfigurationManager::KeyLuaDocumentationType);
const bool hasFile = configurationManager().hasKey(ConfigurationManager::KeyLuaDocumentationFile);
if (hasType && hasFile) {
const std::string LuaDocumentationType =
ConfigurationManager::KeyLuaDocumentation + "." + ConfigurationManager::PartType;
const std::string LuaDocumentationFile =
ConfigurationManager::KeyLuaDocumentation + "." + ConfigurationManager::PartFile;
const bool hasLuaDocType = configurationManager().hasKey(LuaDocumentationType);
const bool hasLuaDocFile = configurationManager().hasKey(LuaDocumentationFile);
if (hasLuaDocType && hasLuaDocFile) {
std::string luaDocumentationType;
configurationManager().getValue(ConfigurationManager::KeyLuaDocumentationType, luaDocumentationType);
configurationManager().getValue(LuaDocumentationType, luaDocumentationType);
std::string luaDocumentationFile;
configurationManager().getValue(ConfigurationManager::KeyLuaDocumentationFile, luaDocumentationFile);
configurationManager().getValue(LuaDocumentationFile, luaDocumentationFile);
luaDocumentationFile = absPath(luaDocumentationFile);
_scriptEngine->writeDocumentation(luaDocumentationFile, luaDocumentationType);
}
// If a general documentation was specified, generate it now
const std::string DocumentationType =
ConfigurationManager::KeyDocumentation + '.' + ConfigurationManager::PartType;
const std::string DocumentationFile =
ConfigurationManager::KeyDocumentation + '.' + ConfigurationManager::PartFile;
const bool hasDocumentationType = configurationManager().hasKey(DocumentationType);
const bool hasDocumentationFile = configurationManager().hasKey(DocumentationFile);
if (hasDocumentationType && hasDocumentationFile) {
std::string documentationType;
configurationManager().getValue(DocumentationType, documentationType);
std::string documentationFile;
configurationManager().getValue(DocumentationFile, documentationFile);
documentationFile = absPath(documentationFile);
DocEng.writeDocumentation(documentationFile, documentationType);
}
const std::string FactoryDocumentationType =
ConfigurationManager::KeyFactoryDocumentation + '.' + ConfigurationManager::PartType;
const std::string FactoryDocumentationFile =
ConfigurationManager::KeyFactoryDocumentation + '.' + ConfigurationManager::PartFile;
bool hasFactoryDocumentationType = configurationManager().hasKey(FactoryDocumentationType);
bool hasFactoryDocumentationFile = configurationManager().hasKey(FactoryDocumentationFile);
if (hasFactoryDocumentationType && hasFactoryDocumentationFile) {
std::string type = configurationManager().value<std::string>(FactoryDocumentationType);
std::string file = configurationManager().value<std::string>(FactoryDocumentationFile);
FactoryManager::ref().writeDocumentation(absPath(file), type);
}
bool disableMasterRendering = false;
configurationManager().getValue(
ConfigurationManager::KeyDisableMasterRendering, disableMasterRendering);
@@ -432,6 +501,9 @@ bool OpenSpaceEngine::initialize() {
// Initialize the InteractionHandler
_interactionHandler->initialize();
// Load a light and a monospaced font
loadFonts();
// Initialize the Scene
Scene* sceneGraph = new Scene;
sceneGraph->initialize();
@@ -453,8 +525,6 @@ bool OpenSpaceEngine::initialize() {
// Run start up scripts
runPreInitializationScripts(scenePath);
// Load a light and a monospaced font
loadFonts();
#ifdef OPENSPACE_MODULE_ONSCREENGUI_ENABLED
LINFO("Initializing GUI");
@@ -507,6 +577,10 @@ bool OpenSpaceEngine::initialize() {
IswaManager::initialize();
#endif
_syncEngine->addSyncables(Time::ref().getSyncables());
_syncEngine->addSyncables(_renderEngine->getSyncables());
_syncEngine->addSyncable(_scriptEngine.get());
LINFO("Finished initializing");
return true;
}
@@ -541,6 +615,14 @@ bool OpenSpaceEngine::gatherCommandlineArguments() {
"the scene file, overriding the value set in the OpenSpace configuration file"
));
commandlineArgumentPlaceholders.cacheFolder = "";
_commandlineParser->addCommand(std::make_unique<SingleCommand<std::string>>(
&commandlineArgumentPlaceholders.cacheFolder, "-cacheDir", "", "Provides the "
"path to a cache file, overriding the value set in the OpenSpace configuration "
"file"
));
return true;
}
@@ -675,12 +757,21 @@ void OpenSpaceEngine::loadFonts() {
}
void OpenSpaceEngine::configureLogging() {
if (configurationManager().hasKeyAndValue<std::string>(ConfigurationManager::KeyLogLevel)) {
const std::string KeyLogLevel =
ConfigurationManager::KeyLogging + '.' + ConfigurationManager::PartLogLevel;
const std::string KeyLogImmediateFlush =
ConfigurationManager::KeyLogging + '.' + ConfigurationManager::PartImmediateFlush;
const std::string KeyLogs =
ConfigurationManager::KeyLogging + '.' + ConfigurationManager::PartLogs;
if (configurationManager().hasKeyAndValue<std::string>(KeyLogLevel)) {
std::string logLevel;
configurationManager().getValue(ConfigurationManager::KeyLogLevel, logLevel);
configurationManager().getValue(KeyLogLevel, logLevel);
bool immediateFlush = false;
configurationManager().getValue(ConfigurationManager::KeyLogImmediateFlush, immediateFlush);
configurationManager().getValue(KeyLogImmediateFlush, immediateFlush);
LogManager::LogLevel level = LogManager::levelFromString(logLevel);
LogManager::deinitialize();
@@ -692,9 +783,9 @@ void OpenSpaceEngine::configureLogging() {
LogMgr.addLog(std::make_unique<ConsoleLog>());
}
if (configurationManager().hasKeyAndValue<ghoul::Dictionary>(ConfigurationManager::KeyLogs)) {
if (configurationManager().hasKeyAndValue<ghoul::Dictionary>(KeyLogs)) {
ghoul::Dictionary logs;
configurationManager().getValue(ConfigurationManager::KeyLogs, logs);
configurationManager().getValue(KeyLogs, logs);
for (size_t i = 1; i <= logs.size(); ++i) {
ghoul::Dictionary logInfo;
@@ -729,6 +820,10 @@ bool OpenSpaceEngine::initializeGL() {
}
#endif
LINFO("Finished initializing OpenGL");
// If using swapgroups,
LINFO("_windowWrapper->isUsingSwapGroups(): " << _windowWrapper->isUsingSwapGroups());
LINFO("_windowWrapper->isSwapGroupMaster(): " << _windowWrapper->isSwapGroupMaster());
return success;
}
@@ -750,24 +845,33 @@ void OpenSpaceEngine::setRunTime(double d){
void OpenSpaceEngine::preSynchronization() {
FileSys.triggerFilesystemEvents();
_syncEngine->presync(_isMaster);
if (_isMaster) {
double dt = _windowWrapper->averageDeltaTime();
_timeManager->preSynchronization(dt);
_scriptEngine->preSynchronization();
auto scheduledScripts = _scriptScheduler->progressTo(Time::ref().j2000Seconds());
while(scheduledScripts.size()){
auto scheduledScript = scheduledScripts.front();
LINFO(scheduledScript);
_scriptEngine->queueScript(scheduledScript, ScriptEngine::RemoteScripting::Yes);
scheduledScripts.pop();
}
_interactionHandler->updateInputStates(dt);
_renderEngine->preSynchronization();
// Update the mouse velocities for interaction handler
_interactionHandler->preSynchronization(dt);
_renderEngine->camera()->preSynchronization();
_renderEngine->updateSceneGraph();
_interactionHandler->updateCamera();
_renderEngine->camera()->invalidateCache();
_parallelConnection->preSynchronization();
}
}
void OpenSpaceEngine::postSynchronizationPreDraw() {
_syncEngine->postsync(_isMaster);
if (_isInShutdownMode) {
if (_shutdownCountdown <= 0.f) {
@@ -776,20 +880,21 @@ void OpenSpaceEngine::postSynchronizationPreDraw() {
_shutdownCountdown -= _windowWrapper->averageDeltaTime();
}
Time::ref().postSynchronizationPreDraw();
_renderEngine->updateFade();
_renderEngine->updateRenderer();
_renderEngine->updateScreenSpaceRenderables();
_renderEngine->updateShaderPrograms();
_scriptEngine->postSynchronizationPreDraw();
_renderEngine->postSynchronizationPreDraw();
// Sync the camera to match the previous frame
_renderEngine->camera()->postSynchronizationPreDraw();
if (!_isMaster) {
_renderEngine->updateSceneGraph();
_renderEngine->camera()->invalidateCache();
}
// Step the camera using the current mouse velocities which are synced
_interactionHandler->postSynchronizationPreDraw();
//_interactionHandler->updateCamera();
// Update the synched variables in the camera class
_renderEngine->camera()->preSynchronization();
_renderEngine->camera()->postSynchronizationPreDraw();
#ifdef OPENSPACE_MODULE_ONSCREENGUI_ENABLED
if (_isMaster && _gui->isEnabled() && _windowWrapper->isRegularRendering()) {
@@ -924,28 +1029,14 @@ void OpenSpaceEngine::mouseScrollWheelCallback(double pos) {
}
void OpenSpaceEngine::encode() {
if (_syncBuffer) {
Time::ref().serialize(_syncBuffer.get());
_scriptEngine->serialize(_syncBuffer.get());
_renderEngine->serialize(_syncBuffer.get());
_interactionHandler->serialize(_syncBuffer.get());
_syncBuffer->write();
}
_syncEngine->encodeSyncables();
_networkEngine->publishStatusMessage();
_networkEngine->sendMessages();
}
void OpenSpaceEngine::decode() {
if (_syncBuffer) {
_syncBuffer->read();
Time::ref().deserialize(_syncBuffer.get());
_scriptEngine->deserialize(_syncBuffer.get());
_renderEngine->deserialize(_syncBuffer.get());
_interactionHandler->deserialize(_syncBuffer.get());
}
_syncEngine->decodeSyncables();
}
void OpenSpaceEngine::externalControlCallback(const char* receivedChars, int size,
@@ -986,6 +1077,14 @@ scripting::LuaLibrary OpenSpaceEngine::luaLibrary() {
};
}
bool OpenSpaceEngine::useBusyWaitForDecode() {
return _settingsEngine->busyWaitForDecode();
}
bool OpenSpaceEngine::logSGCTOutOfOrderErrors() {
return _settingsEngine->logSGCTOutOfOrderErrors();
}
void OpenSpaceEngine::enableBarrier() {
_windowWrapper->setBarrier(true);
}
@@ -1024,6 +1123,11 @@ ScriptEngine& OpenSpaceEngine::scriptEngine() {
return *_scriptEngine;
}
ScriptScheduler& OpenSpaceEngine::scriptScheduler(){
ghoul_assert(_scriptScheduler, "ScriptScheduler must not be nullptr");
return *_scriptScheduler;
}
LuaConsole& OpenSpaceEngine::console() {
ghoul_assert(_console, "LuaConsole must not be nullptr");
return *_console;

View File

@@ -32,12 +32,27 @@
#include <ghoul/ghoul.h>
#include <ghoul/filesystem/filesystem.h>
#include <ghoul/logging/logmanager.h>
#include <string>
namespace {
const std::string _loggerCat = "SettingsEngine";
}
namespace openspace {
SettingsEngine::SettingsEngine()
: _eyeSeparation("eyeSeparation", "Eye Separation" , 0.f, 0.f, 10.f)
, _scenes("scenes", "Scene", properties::OptionProperty::DisplayType::DROPDOWN)
, _showFrameNumber("showFrameNumber", "Show frame number", false)
, _busyWaitForDecode("busyWaitForDecode", "Busy Wait for decode", false)
, _logSGCTOutOfOrderErrors("logSGCTOutOfOrderErrors", "Log SGCT out-of-order", false)
, _useDoubleBuffering("useDoubleBuffering", "Use double buffering", false)
{
setName("Global Properties");
}
@@ -45,6 +60,10 @@ SettingsEngine::SettingsEngine()
void SettingsEngine::initialize() {
initEyeSeparation();
initSceneFiles();
initShowFrameNumber();
initBusyWaitForDecode();
initLogSGCTOutOfOrderErrors();
initUseDoubleBuffering();
}
void SettingsEngine::setModules(std::vector<OpenSpaceModule*> modules) {
@@ -61,6 +80,51 @@ void SettingsEngine::initEyeSeparation() {
[this]() { OsEng.windowWrapper().setEyeSeparationDistance(_eyeSeparation); });
}
void SettingsEngine::initShowFrameNumber() {
addProperty(_showFrameNumber);
_showFrameNumber.onChange(
[this]() { OsEng.renderEngine().setShowFrameNumber(_showFrameNumber.value()); } );
}
void SettingsEngine::initBusyWaitForDecode() {
addProperty(_busyWaitForDecode);
_busyWaitForDecode.onChange(
[this]() {
LINFO((_busyWaitForDecode.value() ? "Busy wait for decode" : "Async decode"));
});
}
bool SettingsEngine::busyWaitForDecode() {
return _busyWaitForDecode.value();
}
void SettingsEngine::initLogSGCTOutOfOrderErrors() {
addProperty(_logSGCTOutOfOrderErrors);
_logSGCTOutOfOrderErrors.onChange(
[this]() {
LINFO("Turn " << (_logSGCTOutOfOrderErrors.value() ? "on" : "off") << " SGCT out of order logging");
});
}
bool SettingsEngine::logSGCTOutOfOrderErrors() {
return _logSGCTOutOfOrderErrors.value();
}
void SettingsEngine::initUseDoubleBuffering() {
addProperty(_useDoubleBuffering);
_useDoubleBuffering.onChange(
[this]() {
LINFO("Turn " << (_useDoubleBuffering.value() ? "on" : "off") << " double buffering");
});
}
bool SettingsEngine::useDoubleBuffering() {
return _useDoubleBuffering.value();
}
void SettingsEngine::initSceneFiles() {
addProperty(_scenes);

95
src/engine/syncengine.cpp Normal file
View File

@@ -0,0 +1,95 @@
/*****************************************************************************************
* *
* 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 <openspace/engine/syncengine.h>
#include <openspace/util/syncdata.h>
#include <openspace/util/syncbuffer.h>
#include <ghoul/logging/logmanager.h>
#include <algorithm>
#include <string>
namespace {
const std::string _loggerCat = "SyncEngine";
}
namespace openspace {
SyncEngine::SyncEngine(SyncBuffer* syncBuffer)
: _syncBuffer(syncBuffer)
{
}
void SyncEngine::presync(bool isMaster) {
for (const auto& syncable : _syncables) {
syncable->presync(isMaster);
}
}
// should be called on sgct master
void SyncEngine::encodeSyncables() {
for (const auto& syncable : _syncables) {
syncable->encode(_syncBuffer.get());
}
_syncBuffer->write();
}
//should be called on sgct slaves
void SyncEngine::decodeSyncables() {
_syncBuffer->read();
for (const auto& syncable : _syncables) {
syncable->decode(_syncBuffer.get());
}
}
void SyncEngine::postsync(bool isMaster) {
for (const auto& syncable : _syncables) {
syncable->postsync(isMaster);
}
}
void SyncEngine::addSyncable(Syncable* syncable) {
_syncables.push_back(syncable);
}
void SyncEngine::addSyncables(const std::vector<Syncable*>& syncables) {
for (const auto& syncable : syncables) {
addSyncable(syncable);
}
}
void SyncEngine::removeSyncable(Syncable* syncable) {
_syncables.erase(
std::remove(_syncables.begin(), _syncables.end(), syncable),
_syncables.end()
);
}
}

View File

@@ -111,8 +111,7 @@ glm::ivec2 SGCTWindowWrapper::currentDrawBufferResolution() const {
int SGCTWindowWrapper::currentNumberOfAaSamples() const {
return sgct::Engine::instance()->getCurrentWindowPtr()->getNumberOfAASamples();
}
}
bool SGCTWindowWrapper::isRegularRendering() const {
// TODO: Needs to implement the nonlinear rendering check ---abock
@@ -136,6 +135,15 @@ bool SGCTWindowWrapper::hasGuiWindow() const {
bool SGCTWindowWrapper::isGuiWindow() const {
return sgct::Engine::instance()->getCurrentWindowPtr()->getName() == GuiWindowName;
}
bool SGCTWindowWrapper::isSwapGroupMaster() const {
return sgct::Engine::instance()->getCurrentWindowPtr()->isSwapGroupMaster();
}
bool SGCTWindowWrapper::isUsingSwapGroups() const {
return sgct::Engine::instance()->getCurrentWindowPtr()->isUsingSwapGroups();
}
glm::mat4 SGCTWindowWrapper::viewProjectionMatrix() const {
return sgct::Engine::instance()->getCurrentModelViewProjectionMatrix();
@@ -177,11 +185,11 @@ bool SGCTWindowWrapper::isSimpleRendering() const {
}
void SGCTWindowWrapper::takeScreenshot() const {
void SGCTWindowWrapper::takeScreenshot(bool applyWarping) const {
sgct::SGCTSettings::instance()->setCaptureFromBackBuffer(applyWarping);
sgct::Engine::instance()->takeScreenshot();
}
//void forEachWindow(std::function<void (void)> function) {
// size_t n = sgct::Engine::instance()->getNumberOfWindows();
// for (size_t i = 0; i < n; ++i)

View File

@@ -86,6 +86,15 @@ bool WindowWrapper::isGuiWindow() const {
return false;
}
bool WindowWrapper::isSwapGroupMaster() const {
return false;
}
bool WindowWrapper::isUsingSwapGroups() const {
return false;
}
glm::mat4 WindowWrapper::viewProjectionMatrix() const {
return glm::mat4(1.f);
}
@@ -119,6 +128,6 @@ bool WindowWrapper::isSimpleRendering() const {
return true;
}
void WindowWrapper::takeScreenshot() const {}
void WindowWrapper::takeScreenshot(bool) const {}
} // namespace openspace

View File

@@ -190,10 +190,6 @@ void InteractionHandler::resetCameraDirection() {
// Update camera Rotation
_camera->setRotation(rotationLookAtFocusNode);
// Explicitly synch
_camera->preSynchronization();
_camera->postSynchronizationPreDraw();
}
void InteractionHandler::setInteractionMode(std::shared_ptr<InteractionMode> interactionMode) {
@@ -230,7 +226,13 @@ void InteractionHandler::unlockControls() {
}
void InteractionHandler::preSynchronization(double deltaTime) {
void InteractionHandler::updateInputStates(double timeSinceLastUpdate) {
ghoul_assert(_inputState != nullptr, "InputState cannot be null!");
ghoul_assert(_camera != nullptr, "Camera cannot be null!");
_currentInteractionMode->updateMouseStatesFromInput(*_inputState, timeSinceLastUpdate);
}
void InteractionHandler::updateCamera() {
ghoul_assert(_inputState != nullptr, "InputState cannot be null!");
ghoul_assert(_camera != nullptr, "Camera cannot be null!");
@@ -238,24 +240,13 @@ void InteractionHandler::preSynchronization(double deltaTime) {
_cameraUpdatedFromScript = false;
}
else {
_currentInteractionMode->updateMouseStatesFromInput(*_inputState, deltaTime);
if (_camera && focusNode()) {
_currentInteractionMode->updateCameraStateFromMouseStates(*_camera);
_camera->setFocusPositionVec3(focusNode()->worldPosition());
}
}
}
void InteractionHandler::postSynchronizationPreDraw() {
ghoul_assert(_inputState != nullptr, "InputState cannot be null!");
ghoul_assert(_camera != nullptr, "Camera cannot be null!");
if (_cameraUpdatedFromScript) {
_cameraUpdatedFromScript = false;
}
else {
_currentInteractionMode->updateCameraStateFromMouseStates(*_camera);
_camera->setFocusPositionVec3(focusNode()->worldPosition());
}
}
SceneGraphNode* const InteractionHandler::focusNode() const {
return _currentInteractionMode->focusNode();
}
@@ -323,10 +314,6 @@ void InteractionHandler::setCameraStateFromDictionary(const ghoul::Dictionary& c
_camera->setPositionVec3(cameraPosition);
_camera->setRotation(glm::dquat(
cameraRotation.x, cameraRotation.y, cameraRotation.z, cameraRotation.w));
// Explicitly synch
_camera->preSynchronization();
_camera->postSynchronizationPreDraw();
}
ghoul::Dictionary InteractionHandler::getCameraStateDictionary() {
@@ -417,7 +404,9 @@ void InteractionHandler::bindKey(Key key, KeyModifier modifier, std::string lua)
void InteractionHandler::writeKeyboardDocumentation(const std::string& type, const std::string& file)
{
if (type == "text") {
std::ofstream f(absPath(file));
std::ofstream f;
f.exceptions(~std::ofstream::goodbit);
f.open(absPath(file));
for (const auto& p : _keyLua) {
std::string remoteScriptingInfo;
@@ -430,6 +419,59 @@ void InteractionHandler::writeKeyboardDocumentation(const std::string& type, con
p.second.first << remoteScriptingInfo << std::endl;
}
}
else if (type == "html") {
std::ofstream f;
f.exceptions(~std::ofstream::goodbit);
f.open(absPath(file));
#ifdef JSON
std::stringstream json;
json << "[";
for (const auto& p : _keyLua) {
json << "{";
json << "\"key\": \"" << std::to_string(p.first) << "\",";
json << "\"script\": \"" << p.second << "\",";
json << "},";
}
json << "]";
std::string jsonText = json.str();
#else
std::stringstream html;
html << "<html>\n"
<< "\t<head>\n"
<< "\t\t<title>Key Bindings</title>\n"
<< "\t</head>\n"
<< "<body>\n"
<< "<table cellpadding=3 cellspacing=0 border=1>\n"
<< "\t<caption>Key Bindings</caption>\n\n"
<< "\t<thead>\n"
<< "\t\t<tr>\n"
<< "\t\t\t<td>Key</td>\n"
<< "\t\t\t<td>Binding</td>\n"
<< "\t\t\t<td>Remote scripting</td>\n"
<< "\t\t</tr>\n"
<< "\t</thead>\n"
<< "\t<tbody>\n";
for (const auto& p : _keyLua) {
html << "\t\t<tr>\n"
<< "\t\t\t<td>" << std::to_string(p.first) << "</td>\n"
<< "\t\t\t<td>" << p.second.first << "</td>\n"
<< "\t\t\t<td>" << (p.second.second ? "Yes" : "No") << "</td>\n"
<< "\t\t</tr>\n";
}
html << "\t</tbody>\n"
<< "</table>\n"
<< "</html>";
f << html.str();
#endif
}
else {
throw ghoul::RuntimeError(
"Unsupported keyboard documentation type '" + type + "'",
@@ -497,17 +539,5 @@ void InteractionHandler::clearKeyframes() {
_inputState->clearKeyframes();
}
void InteractionHandler::serialize(SyncBuffer* syncBuffer) {
for (auto var : _interactionModes) {
var.second->serialize(syncBuffer);
}
}
void InteractionHandler::deserialize(SyncBuffer* syncBuffer) {
for (auto var : _interactionModes) {
var.second->deserialize(syncBuffer);
}
}
} // namespace interaction
} // namespace openspace

View File

@@ -335,55 +335,23 @@ void OrbitalInteractionMode::MouseStates::setVelocityScaleFactor(double scaleFac
}
glm::dvec2 OrbitalInteractionMode::MouseStates::synchedGlobalRotationMouseVelocity() {
return _synchedGlobalRotationMouseVelocity;
return _globalRotationMouseState.velocity.get();
}
glm::dvec2 OrbitalInteractionMode::MouseStates::synchedLocalRotationMouseVelocity() {
return _synchedLocalRotationMouseVelocity;
return _localRotationMouseState.velocity.get();
}
glm::dvec2 OrbitalInteractionMode::MouseStates::synchedTruckMovementMouseVelocity() {
return _synchedTruckMovementMouseVelocity;
return _truckMovementMouseState.velocity.get();
}
glm::dvec2 OrbitalInteractionMode::MouseStates::synchedLocalRollMouseVelocity() {
return _synchedLocalRollMouseVelocity;
return _localRollMouseState.velocity.get();
}
glm::dvec2 OrbitalInteractionMode::MouseStates::synchedGlobalRollMouseVelocity() {
return _synchedGlobalRollMouseVelocity;
}
void OrbitalInteractionMode::MouseStates::preSynchronization() {
_sharedGlobalRotationMouseVelocity = _globalRotationMouseState.velocity.get();
_sharedLocalRotationMouseVelocity = _localRotationMouseState.velocity.get();
_sharedTruckMovementMouseVelocity = _truckMovementMouseState.velocity.get();
_sharedLocalRollMouseVelocity = _localRollMouseState.velocity.get();
_sharedGlobalRollMouseVelocity = _globalRollMouseState.velocity.get();
}
void OrbitalInteractionMode::MouseStates::postSynchronizationPreDraw() {
_synchedGlobalRotationMouseVelocity = _sharedGlobalRotationMouseVelocity;
_synchedLocalRotationMouseVelocity = _sharedLocalRotationMouseVelocity;
_synchedTruckMovementMouseVelocity = _sharedTruckMovementMouseVelocity;
_synchedLocalRollMouseVelocity = _sharedLocalRollMouseVelocity;
_synchedGlobalRollMouseVelocity = _sharedGlobalRollMouseVelocity;
}
void OrbitalInteractionMode::MouseStates::serialize(SyncBuffer* syncBuffer) {
syncBuffer->encode(_sharedGlobalRotationMouseVelocity);
syncBuffer->encode(_sharedLocalRotationMouseVelocity);
syncBuffer->encode(_sharedTruckMovementMouseVelocity);
syncBuffer->encode(_sharedLocalRollMouseVelocity);
syncBuffer->encode(_sharedGlobalRollMouseVelocity);
}
void OrbitalInteractionMode::MouseStates::deserialize(SyncBuffer* syncBuffer) {
syncBuffer->decode(_sharedGlobalRotationMouseVelocity);
syncBuffer->decode(_sharedLocalRotationMouseVelocity);
syncBuffer->decode(_sharedTruckMovementMouseVelocity);
syncBuffer->decode(_sharedLocalRollMouseVelocity);
syncBuffer->decode(_sharedGlobalRollMouseVelocity);
return _globalRollMouseState.velocity.get();
}
OrbitalInteractionMode::OrbitalInteractionMode(std::shared_ptr<MouseStates> mouseStates)
@@ -398,7 +366,6 @@ OrbitalInteractionMode::~OrbitalInteractionMode() {
void OrbitalInteractionMode::updateCameraStateFromMouseStates(Camera& camera) {
// Update synched data
_mouseStates->postSynchronizationPreDraw();
using namespace glm;
if (_focusNode) {
@@ -490,15 +457,6 @@ void OrbitalInteractionMode::updateCameraStateFromMouseStates(Camera& camera) {
void OrbitalInteractionMode::updateMouseStatesFromInput(const InputState& inputState, double deltaTime) {
_mouseStates->updateMouseStatesFromInput(inputState, deltaTime);
_mouseStates->preSynchronization();
}
void OrbitalInteractionMode::serialize(SyncBuffer* syncBuffer) {
_mouseStates->serialize(syncBuffer);
}
void OrbitalInteractionMode::deserialize(SyncBuffer* syncBuffer) {
_mouseStates->deserialize(syncBuffer);
}
GlobeBrowsingInteractionMode::GlobeBrowsingInteractionMode(std::shared_ptr<MouseStates> mouseStates)
@@ -527,9 +485,7 @@ void GlobeBrowsingInteractionMode::setFocusNode(SceneGraphNode* focusNode) {
}
void GlobeBrowsingInteractionMode::updateCameraStateFromMouseStates(Camera& camera) {
// Update synched data
_mouseStates->postSynchronizationPreDraw();
#ifdef OPENSPACE_MODULE_GLOBEBROWSING_ENABLED
using namespace glm;
if (_focusNode && _globe) {

View File

@@ -95,8 +95,8 @@ void NetworkEngine::publishStatusMessage() {
uint16_t messageSize = 0;
double time = Time::ref().currentTime();
std::string timeString = Time::ref().currentTimeUTC();
double time = Time::ref().j2000Seconds();
std::string timeString = Time::ref().UTC();
double delta = Time::ref().deltaTime();
messageSize += sizeof(time);

View File

@@ -994,7 +994,7 @@ void ParallelConnection::sendTimeKeyframe() {
kf._dt = Time::ref().deltaTime();
kf._paused = Time::ref().paused();
kf._requiresTimeJump = _timeJumped;
kf._time = Time::ref().currentTime();
kf._time = Time::ref().j2000Seconds();
//timestamp as current runtime of OpenSpace instance
kf._timestamp = OsEng.runTime();

View File

@@ -173,6 +173,9 @@ PerformanceManager::~PerformanceManager() {
LINFO("Remove shared memory '" << _performanceMemory->name() << "'");
ghoul::SharedMemory::remove(_performanceMemory->name());
_performanceMemory = nullptr;
}
PerformanceManager::destroyGlobalSharedMemory();

View File

@@ -55,10 +55,8 @@ Property::Property(std::string identifier, std::string guiName)
: _owner(nullptr)
, _identifier(std::move(identifier))
{
if (_identifier.empty())
LWARNING("Property identifier is empty");
if (guiName.empty())
LWARNING("Property GUI name is empty");
ghoul_assert(!_identifier.empty(), "Identifier must not be empty");
ghoul_assert(!guiName.empty(), "guiName must not be empty");
setVisible(true);
_metaData.setValue(MetaDataKeyGuiName, std::move(guiName));
@@ -75,8 +73,9 @@ std::string Property::fullyQualifiedIdentifier() const {
PropertyOwner* currentOwner = owner();
while (currentOwner) {
std::string ownerId = currentOwner->name();
if (!ownerId.empty())
if (!ownerId.empty()) {
identifier = ownerId + "." + identifier;
}
currentOwner = currentOwner->owner();
}
return identifier;
@@ -162,19 +161,18 @@ void Property::onChange(std::function<void()> callback) {
_onChangeCallback = std::move(callback);
}
PropertyOwner* Property::owner() const
{
PropertyOwner* Property::owner() const {
return _owner;
}
void Property::setPropertyOwner(PropertyOwner* owner)
{
void Property::setPropertyOwner(PropertyOwner* owner) {
_owner = owner;
}
void Property::notifyListener() {
if (_onChangeCallback)
if (_onChangeCallback) {
_onChangeCallback();
}
}
std::string Property::generateBaseDescription() const {

View File

@@ -28,6 +28,7 @@
#include <openspace/engine/openspaceengine.h>
#include <openspace/engine/wrapper/windowwrapper.h>
#include <openspace/rendering/renderengine.h>
#include <openspace/rendering/renderable.h>
#include <openspace/rendering/volumeraycaster.h>
#include <openspace/scene/scene.h>
#include <openspace/util/camera.h>
@@ -260,7 +261,12 @@ void ABufferRenderer::render(float blackoutFactor, bool doPerformanceMeasurement
glBindImageTexture(1, _fragmentTexture, 0, GL_FALSE, 0, GL_READ_WRITE, GL_RGBA32UI);
// Render the scene to the fragment buffer. Collect renderer tasks (active raycasters)
RenderData data{ *_camera, psc(), doPerformanceMeasurements };
int renderBinMask = static_cast<int>(Renderable::RenderBin::Background) |
static_cast<int>(Renderable::RenderBin::Opaque) |
static_cast<int>(Renderable::RenderBin::Transparent) |
static_cast<int>(Renderable::RenderBin::Overlay);
RenderData data{ *_camera, psc(), doPerformanceMeasurements, renderBinMask };
RendererTasks tasks;
_scene->render(data, tasks);

View File

@@ -30,6 +30,7 @@
#include <openspace/scene/scene.h>
#include <openspace/util/camera.h>
#include <openspace/engine/openspaceengine.h>
#include <openspace/rendering/renderable.h>
#include <openspace/rendering/volumeraycaster.h>
#include <openspace/rendering/raycastermanager.h>
@@ -329,7 +330,7 @@ void FramebufferRenderer::render(float blackoutFactor, bool doPerformanceMeasure
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
RenderData data = { *_camera, psc(), doPerformanceMeasurements };
RenderData data = { *_camera, psc(), doPerformanceMeasurements, 0 };
RendererTasks tasks;
// Capture standard fbo
@@ -339,7 +340,13 @@ void FramebufferRenderer::render(float blackoutFactor, bool doPerformanceMeasure
glBindFramebuffer(GL_FRAMEBUFFER, _mainFramebuffer);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// bind new fbo A with color and depth buffer.
data.renderBinMask = static_cast<int>(Renderable::RenderBin::Background);
_scene->render(data, tasks);
data.renderBinMask = static_cast<int>(Renderable::RenderBin::Opaque);
_scene->render(data, tasks);
data.renderBinMask = static_cast<int>(Renderable::RenderBin::Transparent);
_scene->render(data, tasks);
data.renderBinMask = static_cast<int>(Renderable::RenderBin::Overlay);
_scene->render(data, tasks);
for (const RaycasterTask& raycasterTask : tasks.raycasterTasks) {

View File

@@ -22,14 +22,14 @@
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
// open space includes
#include <openspace/rendering/renderable.h>
#include <openspace/util/factorymanager.h>
#include <openspace/util/updatestructures.h>
#include <openspace/util/spicemanager.h>
#include <openspace/scene/scenegraphnode.h>
// ghoul
#include <openspace/documentation/verifier.h>
#include <ghoul/misc/dictionary.h>
#include <ghoul/filesystem/filesystem.h>
#include <ghoul/opengl/programobject.h>
@@ -44,22 +44,37 @@ namespace {
namespace openspace {
Documentation Renderable::Documentation() {
using namespace openspace::documentation;
return {
"Renderable",
"renderable",
{
{
KeyType,
new StringAnnotationVerifier("A valid Renderable created by a factory"),
"This key specifies the type of Renderable that gets created. It has to be one"
"of the valid Renderables that are available for creation (see the "
"FactoryDocumentation for a list of possible Renderables), which depends on "
"the configration of the application",
Optional::No
}
}
};
}
Renderable* Renderable::createFromDictionary(const ghoul::Dictionary& dictionary) {
// The name is passed down from the SceneGraphNode
std::string name;
bool success = dictionary.getValue(SceneGraphNode::KeyName, name);
assert(success);
ghoul_assert(success, "The SceneGraphNode did not set the 'name' key");
std::string renderableType;
success = dictionary.getValue(KeyType, renderableType);
documentation::testSpecificationAndThrow(Documentation(), dictionary, "Renderable");
if (!success) {
LERROR("Renderable '" << name << "' did not have key '" << KeyType << "'");
return nullptr;
}
std::string renderableType = dictionary.value<std::string>(KeyType);
ghoul::TemplateFactory<Renderable>* factory
= FactoryManager::ref().factory<Renderable>();
auto factory = FactoryManager::ref().factory<Renderable>();
Renderable* result = factory->create(renderableType, dictionary);
if (result == nullptr) {
LERROR("Failed to create a Renderable object of type '" << renderableType << "'");
@@ -71,66 +86,55 @@ Renderable* Renderable::createFromDictionary(const ghoul::Dictionary& dictionary
Renderable::Renderable()
: _enabled("enabled", "Is Enabled", true)
, _renderBin(RenderBin::Opaque)
, _startTime("")
, _endTime("")
, _hasTimeInterval(false)
{
}
{}
Renderable::Renderable(const ghoul::Dictionary& dictionary)
: _enabled("enabled", "Is Enabled", true)
, _renderBin(RenderBin::Opaque)
, _startTime("")
, _endTime("")
, _hasTimeInterval(false)
{
setName("renderable");
#ifndef NDEBUG
std::string name;
ghoul_assert(dictionary.getValue(SceneGraphNode::KeyName, name),
"Scenegraphnode need to specify '" << SceneGraphNode::KeyName
<< "' because renderables is going to use this for debugging!");
#endif
ghoul_assert(
dictionary.hasKeyAndValue<std::string>(SceneGraphNode::KeyName),
"SceneGraphNode must specify '" << SceneGraphNode::KeyName << "'"
);
dictionary.getValue(keyStart, _startTime);
dictionary.getValue(keyEnd, _endTime);
if (_startTime != "" && _endTime != "")
if (_startTime != "" && _endTime != "") {
_hasTimeInterval = true;
}
addProperty(_enabled);
}
Renderable::~Renderable() {
Renderable::~Renderable() {}
void Renderable::setBoundingSphere(PowerScaledScalar boundingSphere) {
boundingSphere_ = std::move(boundingSphere);
}
void Renderable::setBoundingSphere(const PowerScaledScalar& boundingSphere)
{
boundingSphere_ = boundingSphere;
}
const PowerScaledScalar& Renderable::getBoundingSphere()
{
PowerScaledScalar Renderable::getBoundingSphere() {
return boundingSphere_;
}
void Renderable::update(const UpdateData&)
{
}
void Renderable::update(const UpdateData&) {}
void Renderable::render(const RenderData& data, RendererTasks& tasks)
{
(void) tasks;
void Renderable::render(const RenderData& data, RendererTasks&) {
render(data);
}
void Renderable::render(const RenderData& data)
{
}
void Renderable::render(const RenderData& data) {}
void Renderable::postRender(const RenderData& data)
{
}
void Renderable::postRender(const RenderData& data) {}
void Renderable::setPscUniforms(
ghoul::opengl::ProgramObject& program,
@@ -143,6 +147,18 @@ void Renderable::setPscUniforms(
program.setUniform("scaling", camera.scaling());
}
Renderable::RenderBin Renderable::renderBin() const {
return _renderBin;
}
void Renderable::setRenderBin(RenderBin bin) {
_renderBin = bin;
}
bool Renderable::matchesRenderBinMask(int binMask) {
return binMask & static_cast<int>(renderBin());
}
bool Renderable::isVisible() const {
return _enabled;
}

View File

@@ -40,6 +40,7 @@
#include <openspace/performance/performancemanager.h>
#include <openspace/documentation/documentationengine.h>
#include <openspace/engine/openspaceengine.h>
#include <openspace/interaction/interactionhandler.h>
#include <openspace/scene/scene.h>
@@ -124,10 +125,12 @@ RenderEngine::RenderEngine()
, _showInfo(true)
, _showLog(true)
, _takeScreenshot(false)
, _showFrameNumber(false)
, _globalBlackOutFactor(1.f)
, _fadeDuration(2.f)
, _currentFadeTime(0.f)
, _fadeDirection(0)
, _frameNumber(0)
, _frametimeType(FrametimeType::DtTimeAvg)
// , _sgctRenderStatisticsVisible(false)
{
@@ -180,6 +183,7 @@ void RenderEngine::setRendererFromString(const std::string& renderingMethod) {
}
bool RenderEngine::initialize() {
_frameNumber = 0;
std::string renderingMethod = DefaultRenderingMethod;
// If the user specified a rendering method that he would like to use, use that
@@ -228,6 +232,7 @@ bool RenderEngine::initialize() {
MissionManager::initialize();
#endif
return true;
}
@@ -240,6 +245,8 @@ bool RenderEngine::initializeGL() {
OsEng.windowWrapper().setNearFarClippingPlane(0.001f, 1000.f);
try {
const float fontSizeBig = 50.f;
_fontBig = OsEng.fontManager().font(KeyFontMono, fontSizeBig);
const float fontSizeTime = 15.f;
_fontDate = OsEng.fontManager().font(KeyFontMono, fontSizeTime);
const float fontSizeMono = 10.f;
@@ -334,23 +341,69 @@ bool RenderEngine::initializeGL() {
return true;
}
void RenderEngine::preSynchronization() {
//if (_mainCamera)
// _mainCamera->preSynchronization();
void RenderEngine::updateSceneGraph() {
_sceneGraph->update({
glm::dvec3(0),
glm::dmat3(1),
1,
Time::ref().j2000Seconds(),
Time::ref().timeJumped(),
Time::ref().deltaTime(),
_performanceManager != nullptr
});
_sceneGraph->evaluate(_mainCamera);
//Allow focus node to update camera (enables camera-following)
//FIX LATER: THIS CAUSES MASTER NODE TO BE ONE FRAME AHEAD OF SLAVES
//if (const SceneGraphNode* node = OsEng.ref().interactionHandler().focusNode()){
//node->updateCamera(_mainCamera);
//}
}
void RenderEngine::postSynchronizationPreDraw() {
void RenderEngine::updateShaderPrograms() {
for (auto program : _programs) {
try {
if (program->isDirty()) {
program->rebuildFromFile();
}
}
catch (const ghoul::opengl::ShaderObject::ShaderCompileError& e) {
LERRORC(e.component, e.what());
}
}
}
void RenderEngine::updateRenderer() {
bool windowResized = OsEng.windowWrapper().windowHasResized();
if (windowResized) {
glm::ivec2 res = OsEng.windowWrapper().currentDrawBufferResolution();
_renderer->setResolution(res);
ghoul::fontrendering::FontRenderer::defaultRenderer().setFramebufferSize(glm::vec2(res));
}
_renderer->update();
}
void RenderEngine::updateScreenSpaceRenderables() {
for (auto screenspacerenderable : _screenSpaceRenderables) {
screenspacerenderable->update();
}
}
void RenderEngine::updateFade() {
//temporary fade funtionality
float fadedIn = 1.0;
float fadedOut = 0.0;
// Don't restart the fade if you've already done it in that direction
if ( (_fadeDirection > 0 && _globalBlackOutFactor == fadedIn)
|| (_fadeDirection < 0 && _globalBlackOutFactor == fadedOut)) {
if ((_fadeDirection > 0 && _globalBlackOutFactor == fadedIn)
|| (_fadeDirection < 0 && _globalBlackOutFactor == fadedOut)) {
_fadeDirection = 0;
}
if (_fadeDirection != 0) {
if (_currentFadeTime > _fadeDuration){
if (_currentFadeTime > _fadeDuration) {
_globalBlackOutFactor = _fadeDirection > 0 ? fadedIn : fadedOut;
_fadeDirection = 0;
}
@@ -362,52 +415,6 @@ void RenderEngine::postSynchronizationPreDraw() {
_currentFadeTime += static_cast<float>(OsEng.windowWrapper().averageDeltaTime());
}
}
//if (_mainCamera)
// _mainCamera->postSynchronizationPreDraw();
bool windowResized = OsEng.windowWrapper().windowHasResized();
if (windowResized) {
glm::ivec2 res = OsEng.windowWrapper().currentDrawBufferResolution();
_renderer->setResolution(res);
ghoul::fontrendering::FontRenderer::defaultRenderer().setFramebufferSize(glm::vec2(res));
}
// update and evaluate the scene starting from the root node
_sceneGraph->update({
glm::dvec3(0),
glm::dmat3(1),
1,
Time::ref().currentTime(),
Time::ref().timeJumped(),
Time::ref().deltaTime(),
_performanceManager != nullptr
});
_sceneGraph->evaluate(_mainCamera);
_renderer->update();
for (auto program : _programs) {
try {
if (program->isDirty()) {
program->rebuildFromFile();
}
}
catch (const ghoul::opengl::ShaderObject::ShaderCompileError& e) {
LERRORC(e.component, e.what());
}
}
for (auto screenspacerenderable : _screenSpaceRenderables) {
screenspacerenderable->update();
}
//Allow focus node to update camera (enables camera-following)
//FIX LATER: THIS CAUSES MASTER NODE TO BE ONE FRAME AHEAD OF SLAVES
//if (const SceneGraphNode* node = OsEng.ref().interactionHandler().focusNode()){
//node->updateCamera(_mainCamera);
//}
}
void RenderEngine::render(const glm::mat4& projectionMatrix, const glm::mat4& viewMatrix){
@@ -420,10 +427,20 @@ void RenderEngine::render(const glm::mat4& projectionMatrix, const glm::mat4& vi
// Print some useful information on the master viewport
if (OsEng.isMaster() && OsEng.windowWrapper().isSimpleRendering()) {
if (_showInfo) {
renderInformation();
}
renderInformation();
}
glm::vec2 penPosition = glm::vec2(
OsEng.windowWrapper().viewportPixelCoordinates().y / 2 - 50,
OsEng.windowWrapper().viewportPixelCoordinates().w / 3
);
if(_showFrameNumber) {
RenderFontCr(*_fontBig, penPosition, "%i", _frameNumber);
}
_frameNumber++;
for (auto screenSpaceRenderable : _screenSpaceRenderables) {
if (screenSpaceRenderable->isEnabled() && screenSpaceRenderable->isReady())
@@ -462,7 +479,7 @@ void RenderEngine::postDraw() {
}
if (_takeScreenshot) {
OsEng.windowWrapper().takeScreenshot();
OsEng.windowWrapper().takeScreenshot(_applyWarping);
_takeScreenshot = false;
}
@@ -471,8 +488,9 @@ void RenderEngine::postDraw() {
}
}
void RenderEngine::takeScreenshot() {
void RenderEngine::takeScreenshot(bool applyWarping) {
_takeScreenshot = true;
_applyWarping = applyWarping;
}
void RenderEngine::toggleInfoText(bool b) {
@@ -495,8 +513,7 @@ void RenderEngine::toggleFrametimeType(int t) {
}
Scene* RenderEngine::scene() {
// TODO custom assert (ticket #5)
assert(_sceneGraph);
ghoul_assert(_sceneGraph, "Scenegraph not initialized");
return _sceneGraph;
}
@@ -508,29 +525,6 @@ void RenderEngine::setSceneGraph(Scene* sceneGraph) {
_sceneGraph = sceneGraph;
}
void RenderEngine::serialize(SyncBuffer* syncBuffer) {
if (_mainCamera){
_mainCamera->serialize(syncBuffer);
}
syncBuffer->encode(_onScreenInformation._node);
syncBuffer->encode(_onScreenInformation._position.x);
syncBuffer->encode(_onScreenInformation._position.y);
syncBuffer->encode(_onScreenInformation._size);
}
void RenderEngine::deserialize(SyncBuffer* syncBuffer) {
if (_mainCamera){
_mainCamera->deserialize(syncBuffer);
}
syncBuffer->decode(_onScreenInformation._node);
syncBuffer->decode(_onScreenInformation._position.x);
syncBuffer->decode(_onScreenInformation._position.y);
syncBuffer->decode(_onScreenInformation._size);
}
Camera* RenderEngine::camera() const {
return _mainCamera;
}
@@ -720,14 +714,16 @@ void RenderEngine::setNAaSamples(int nAaSamples) {
}
scripting::LuaLibrary RenderEngine::luaLibrary() {
return {
return{
"",
{
{
"takeScreenshot",
&luascriptfunctions::takeScreenshot,
"",
"Renders the current image to a file on disk"
"(optional bool)",
"Renders the current image to a file on disk. If the boolean parameter "
"is set to 'true', the screenshot will include the blending and the "
"meshes. If it is 'false', the straight FBO will be recorded."
},
{
"setRenderer",
@@ -739,7 +735,7 @@ scripting::LuaLibrary RenderEngine::luaLibrary() {
"setNAaSamples",
&luascriptfunctions::setNAaSamples,
"int",
"Sets the number of anti-aliasing (msaa) samples"
"Sets the number of anti-aliasing (MSAA) samples"
},
{
"showRenderInformation",
@@ -1202,6 +1198,10 @@ void RenderEngine::changeViewPoint(std::string origin) {
LFATAL("This function is being misused with an argument of '" << origin << "'");
}
void RenderEngine::setShowFrameNumber(bool enabled){
_showFrameNumber = enabled;
}
void RenderEngine::setDisableRenderingOnMaster(bool enabled) {
_disableMasterRendering = enabled;
}
@@ -1281,7 +1281,7 @@ void RenderEngine::renderInformation() {
using Font = ghoul::fontrendering::Font;
using ghoul::fontrendering::RenderFont;
if (_showInfo && _fontDate && _fontInfo) {
if (_fontDate) {
glm::vec2 penPosition = glm::vec2(
10.f,
OsEng.windowWrapper().viewportPixelCoordinates().w
@@ -1291,45 +1291,46 @@ void RenderEngine::renderInformation() {
RenderFontCr(*_fontDate,
penPosition,
"Date: %s",
Time::ref().currentTimeUTC().c_str()
Time::ref().UTC().c_str()
);
RenderFontCr(*_fontInfo,
penPosition,
"Simulation increment (s): %.0f",
Time::ref().deltaTime()
if (_showInfo && _fontInfo) {
RenderFontCr(*_fontInfo,
penPosition,
"Simulation increment (s): %.0f",
Time::ref().deltaTime()
);
switch (_frametimeType) {
case FrametimeType::DtTimeAvg:
RenderFontCr(*_fontInfo,
penPosition,
"Avg. Frametime: %.5f",
OsEng.windowWrapper().averageDeltaTime()
);
break;
case FrametimeType::FPS:
RenderFontCr(*_fontInfo,
penPosition,
"FPS: %3.2f",
1.0 / OsEng.windowWrapper().deltaTime()
);
break;
case FrametimeType::FPSAvg:
RenderFontCr(*_fontInfo,
penPosition,
"Avg. FPS: %3.2f",
1.0 / OsEng.windowWrapper().averageDeltaTime()
);
break;
default:
RenderFontCr(*_fontInfo,
penPosition,
"Avg. Frametime: %.5f",
OsEng.windowWrapper().averageDeltaTime()
);
break;
}
switch (_frametimeType) {
case FrametimeType::DtTimeAvg:
RenderFontCr(*_fontInfo,
penPosition,
"Avg. Frametime: %.5f",
OsEng.windowWrapper().averageDeltaTime()
);
break;
case FrametimeType::FPS:
RenderFontCr(*_fontInfo,
penPosition,
"FPS: %3.2f",
1.0 / OsEng.windowWrapper().deltaTime()
);
break;
case FrametimeType::FPSAvg:
RenderFontCr(*_fontInfo,
penPosition,
"Avg. FPS: %3.2f",
1.0 / OsEng.windowWrapper().averageDeltaTime()
);
break;
default:
RenderFontCr(*_fontInfo,
penPosition,
"Avg. Frametime: %.5f",
OsEng.windowWrapper().averageDeltaTime()
);
break;
}
network::Status status = OsEng.parallelConnection().status();
size_t nConnections = OsEng.parallelConnection().nConnections();
@@ -1371,260 +1372,270 @@ void RenderEngine::renderInformation() {
#ifdef OPENSPACE_MODULE_NEWHORIZONS_ENABLED
//<<<<<<< HEAD
bool hasNewHorizons = scene()->sceneGraphNode("NewHorizons");
double currentTime = Time::ref().currentTime();
double currentTime = Time::ref().j2000Seconds();
if (MissionManager::ref().hasCurrentMission()) {
const Mission& mission = MissionManager::ref().currentMission();
//=======
// bool hasNewHorizons = scene()->sceneGraphNode("NewHorizons");
// double currentTime = Time::ref().currentTime();
//>>>>>>> develop
//
// if (MissionManager::ref().hasCurrentMission()) {
//
// const Mission& mission = MissionManager::ref().currentMission();
if (mission.phases().size() > 0) {
if (mission.phases().size() > 0) {
static const glm::vec4 nextMissionColor(0.7, 0.3, 0.3, 1);
//static const glm::vec4 missionProgressColor(0.4, 1.0, 1.0, 1);
static const glm::vec4 currentMissionColor(0.0, 0.5, 0.5, 1);
static const glm::vec4 missionProgressColor = currentMissionColor;// (0.4, 1.0, 1.0, 1);
static const glm::vec4 currentLeafMissionColor = missionProgressColor;
static const glm::vec4 nonCurrentMissionColor(0.3, 0.3, 0.3, 1);
static const glm::vec4 nextMissionColor(0.7, 0.3, 0.3, 1);
//static const glm::vec4 missionProgressColor(0.4, 1.0, 1.0, 1);
static const glm::vec4 currentMissionColor(0.0, 0.5, 0.5, 1);
static const glm::vec4 missionProgressColor = currentMissionColor;// (0.4, 1.0, 1.0, 1);
static const glm::vec4 currentLeafMissionColor = missionProgressColor;
static const glm::vec4 nonCurrentMissionColor(0.3, 0.3, 0.3, 1);
// Add spacing
RenderFontCr(*_fontInfo, penPosition, nonCurrentMissionColor, " ");
// Add spacing
RenderFontCr(*_fontInfo, penPosition, nonCurrentMissionColor, " ");
std::list<const MissionPhase*> phaseTrace = mission.phaseTrace(currentTime);
std::list<const MissionPhase*> phaseTrace = mission.phaseTrace(currentTime);
if (phaseTrace.size()) {
std::string title = "Current Mission Phase: " + phaseTrace.back()->name();
RenderFontCr(*_fontInfo, penPosition, missionProgressColor, title.c_str());
double remaining = phaseTrace.back()->timeRange().end - currentTime;
float t = static_cast<float>(1.0 - remaining / phaseTrace.back()->timeRange().duration());
std::string progress = progressToStr(25, t);
//RenderFontCr(*_fontInfo, penPosition, missionProgressColor,
// "%.0f s %s %.1f %%", remaining, progress.c_str(), t * 100);
}
else {
RenderFontCr(*_fontInfo, penPosition, nextMissionColor, "Next Mission:");
double remaining = mission.timeRange().start - currentTime;
RenderFontCr(*_fontInfo, penPosition, nextMissionColor,
"%.0f s", remaining);
}
bool showAllPhases = false;
typedef std::pair<const MissionPhase*, int> PhaseWithDepth;
std::stack<PhaseWithDepth> S;
int pixelIndentation = 20;
S.push({ &mission, 0 });
while (!S.empty()) {
const MissionPhase* phase = S.top().first;
int depth = S.top().second;
S.pop();
bool isCurrentPhase = phase->timeRange().includes(currentTime);
penPosition.x += depth * pixelIndentation;
if (isCurrentPhase) {
double remaining = phase->timeRange().end - currentTime;
float t = static_cast<float>(1.0 - remaining / phase->timeRange().duration());
if (phaseTrace.size()) {
std::string title = "Current Mission Phase: " + phaseTrace.back()->name();
RenderFontCr(*_fontInfo, penPosition, missionProgressColor, title.c_str());
double remaining = phaseTrace.back()->timeRange().end - currentTime;
float t = static_cast<float>(1.0 - remaining / phaseTrace.back()->timeRange().duration());
std::string progress = progressToStr(25, t);
RenderFontCr(*_fontInfo, penPosition, currentMissionColor,
"%s %s %.1f %%",
phase->name().c_str(),
progress.c_str(),
t * 100
);
//RenderFontCr(*_fontInfo, penPosition, missionProgressColor,
// "%.0f s %s %.1f %%", remaining, progress.c_str(), t * 100);
}
else {
RenderFontCr(*_fontInfo, penPosition, nonCurrentMissionColor, phase->name().c_str());
RenderFontCr(*_fontInfo, penPosition, nextMissionColor, "Next Mission:");
double remaining = mission.timeRange().start - currentTime;
RenderFontCr(*_fontInfo, penPosition, nextMissionColor,
"%.0f s", remaining);
}
penPosition.x -= depth * pixelIndentation;
if (isCurrentPhase || showAllPhases) {
// phases are sorted increasingly by start time, and will be popped
// last-in-first-out from the stack, so add them in reversed order.
int indexLastPhase = phase->phases().size() - 1;
for (int i = indexLastPhase; 0 <= i; --i) {
S.push({ &phase->phase(i), depth + 1 });
}
}
}
}
}
bool showAllPhases = false;
typedef std::pair<const MissionPhase*, int> PhaseWithDepth;
std::stack<PhaseWithDepth> S;
int pixelIndentation = 20;
S.push({ &mission, 0 });
while (!S.empty()) {
const MissionPhase* phase = S.top().first;
int depth = S.top().second;
S.pop();
bool isCurrentPhase = phase->timeRange().includes(currentTime);
if (openspace::ImageSequencer::ref().isReady()) {
penPosition.y -= 25.f;
glm::vec4 targetColor(0.00, 0.75, 1.00, 1);
if (hasNewHorizons) {
try {
double lt;
glm::dvec3 p =
SpiceManager::ref().targetPosition("PLUTO", "NEW HORIZONS", "GALACTIC", {}, currentTime, lt);
psc nhPos = PowerScaledCoordinate::CreatePowerScaledCoordinate(p.x, p.y, p.z);
float a, b, c;
glm::dvec3 radii;
SpiceManager::ref().getValue("PLUTO", "RADII", radii);
a = radii.x;
b = radii.y;
float radius = (a + b) / 2.f;
float distToSurf = glm::length(nhPos.vec3()) - radius;
RenderFont(*_fontInfo,
penPosition,
"Distance to Pluto: % .1f (KM)",
distToSurf
);
penPosition.y -= _fontInfo->height();
}
catch (...) {
}
}
double remaining = openspace::ImageSequencer::ref().getNextCaptureTime() - currentTime;
float t = static_cast<float>(1.0 - remaining / openspace::ImageSequencer::ref().getIntervalLength());
std::string str = SpiceManager::ref().dateFromEphemerisTime(
ImageSequencer::ref().getNextCaptureTime(),
"YYYY MON DD HR:MN:SC"
);
glm::vec4 active(0.6, 1, 0.00, 1);
glm::vec4 brigther_active(0.9, 1, 0.75, 1);
if (remaining > 0) {
std::string progress = progressToStr(25, t);
brigther_active *= (1 - t);
RenderFontCr(*_fontInfo,
penPosition,
active * t + brigther_active,
"Next instrument activity:"
);
RenderFontCr(*_fontInfo,
penPosition,
active * t + brigther_active,
"%.0f s %s %.1f %%",
remaining, progress.c_str(), t * 100
);
RenderFontCr(*_fontInfo,
penPosition,
active,
"Data acquisition time: %s",
str.c_str()
);
}
std::pair<double, std::string> nextTarget = ImageSequencer::ref().getNextTarget();
std::pair<double, std::string> currentTarget = ImageSequencer::ref().getCurrentTarget();
if (currentTarget.first > 0.0) {
int timeleft = static_cast<int>(nextTarget.first - currentTime);
int hour = timeleft / 3600;
int second = timeleft % 3600;
int minute = second / 60;
second = second % 60;
std::string hh, mm, ss;
if (hour < 10)
hh.append("0");
if (minute < 10)
mm.append("0");
if (second < 10)
ss.append("0");
hh.append(std::to_string(hour));
mm.append(std::to_string(minute));
ss.append(std::to_string(second));
RenderFontCr(*_fontInfo,
penPosition,
targetColor,
"Data acquisition adjacency: [%s:%s:%s]",
hh.c_str(), mm.c_str(), ss.c_str()
);
#if 0
// Why is it (2) in the original? ---abock
//std::pair<double, std::vector<std::string>> incidentTargets = ImageSequencer::ref().getIncidentTargetList(0);
//std::pair<double, std::vector<std::string>> incidentTargets = ImageSequencer::ref().getIncidentTargetList(2);
std::string space;
glm::vec4 color;
size_t isize = incidentTargets.second.size();
for (size_t p = 0; p < isize; p++) {
double t = static_cast<double>(p + 1) / static_cast<double>(isize + 1);
t = (p > isize / 2) ? 1 - t : t;
t += 0.3;
color = (p == isize / 2) ? targetColor : glm::vec4(t, t, t, 1);
RenderFont(*_fontInfo,
penPosition,
color,
"%s%s",
space.c_str(), incidentTargets.second[p].c_str()
);
for (int k = 0; k < incidentTargets.second[p].size() + 2; k++)
space += " ";
}
#endif
penPosition.y -= _fontInfo->height();
std::map<std::string, bool> activeMap = ImageSequencer::ref().getActiveInstruments();
glm::vec4 firing(0.58 - t, 1 - t, 1 - t, 1);
glm::vec4 notFiring(0.5, 0.5, 0.5, 1);
RenderFontCr(*_fontInfo,
penPosition,
active,
"Active Instruments:"
);
for (auto t : activeMap) {
if (t.second == false) {
RenderFont(*_fontInfo,
penPosition,
glm::vec4(0.3, 0.3, 0.3, 1),
"| |"
);
RenderFontCr(*_fontInfo,
penPosition,
glm::vec4(0.3, 0.3, 0.3, 1),
" %5s",
t.first.c_str()
);
}
else {
RenderFont(*_fontInfo,
penPosition,
glm::vec4(0.3, 0.3, 0.3, 1),
"|"
);
if (t.first == "NH_LORRI") {
RenderFont(*_fontInfo,
penPosition,
firing,
" + "
penPosition.x += depth * pixelIndentation;
if (isCurrentPhase) {
double remaining = phase->timeRange().end - currentTime;
float t = static_cast<float>(1.0 - remaining / phase->timeRange().duration());
std::string progress = progressToStr(25, t);
RenderFontCr(*_fontInfo, penPosition, currentMissionColor,
"%s %s %.1f %%",
phase->name().c_str(),
progress.c_str(),
t * 100
);
}
else {
RenderFontCr(*_fontInfo, penPosition, nonCurrentMissionColor, phase->name().c_str());
}
penPosition.x -= depth * pixelIndentation;
if (isCurrentPhase || showAllPhases) {
// phases are sorted increasingly by start time, and will be popped
// last-in-first-out from the stack, so add them in reversed order.
int indexLastPhase = phase->phases().size() - 1;
for (int i = indexLastPhase; 0 <= i; --i) {
S.push({ &phase->phase(i), depth + 1 });
}
}
}
}
}
if (openspace::ImageSequencer::ref().isReady()) {
penPosition.y -= 25.f;
glm::vec4 targetColor(0.00, 0.75, 1.00, 1);
if (hasNewHorizons) {
try {
double lt;
glm::dvec3 p =
SpiceManager::ref().targetPosition("PLUTO", "NEW HORIZONS", "GALACTIC", {}, currentTime, lt);
psc nhPos = PowerScaledCoordinate::CreatePowerScaledCoordinate(p.x, p.y, p.z);
float a, b, c;
glm::dvec3 radii;
SpiceManager::ref().getValue("PLUTO", "RADII", radii);
a = radii.x;
b = radii.y;
float radius = (a + b) / 2.f;
float distToSurf = glm::length(nhPos.vec3()) - radius;
RenderFont(*_fontInfo,
penPosition,
"Distance to Pluto: % .1f (KM)",
distToSurf
);
penPosition.y -= _fontInfo->height();
}
catch (...) {
}
}
double remaining = openspace::ImageSequencer::ref().getNextCaptureTime() - currentTime;
float t = static_cast<float>(1.0 - remaining / openspace::ImageSequencer::ref().getIntervalLength());
std::string str = SpiceManager::ref().dateFromEphemerisTime(
ImageSequencer::ref().getNextCaptureTime(),
"YYYY MON DD HR:MN:SC"
);
glm::vec4 active(0.6, 1, 0.00, 1);
glm::vec4 brigther_active(0.9, 1, 0.75, 1);
if (remaining > 0) {
std::string progress = progressToStr(25, t);
brigther_active *= (1 - t);
RenderFontCr(*_fontInfo,
penPosition,
active * t + brigther_active,
"Next instrument activity:"
);
RenderFontCr(*_fontInfo,
penPosition,
active * t + brigther_active,
"%.0f s %s %.1f %%",
remaining, progress.c_str(), t * 100
);
RenderFontCr(*_fontInfo,
penPosition,
active,
"Data acquisition time: %s",
str.c_str()
);
}
std::pair<double, std::string> nextTarget = ImageSequencer::ref().getNextTarget();
std::pair<double, std::string> currentTarget = ImageSequencer::ref().getCurrentTarget();
if (currentTarget.first > 0.0) {
int timeleft = static_cast<int>(nextTarget.first - currentTime);
int hour = timeleft / 3600;
int second = timeleft % 3600;
int minute = second / 60;
second = second % 60;
std::string hh, mm, ss;
if (hour < 10)
hh.append("0");
if (minute < 10)
mm.append("0");
if (second < 10)
ss.append("0");
hh.append(std::to_string(hour));
mm.append(std::to_string(minute));
ss.append(std::to_string(second));
RenderFontCr(*_fontInfo,
penPosition,
targetColor,
"Data acquisition adjacency: [%s:%s:%s]",
hh.c_str(), mm.c_str(), ss.c_str()
);
#if 0
// Why is it (2) in the original? ---abock
//std::pair<double, std::vector<std::string>> incidentTargets = ImageSequencer::ref().getIncidentTargetList(0);
//std::pair<double, std::vector<std::string>> incidentTargets = ImageSequencer::ref().getIncidentTargetList(2);
std::string space;
glm::vec4 color;
size_t isize = incidentTargets.second.size();
for (size_t p = 0; p < isize; p++) {
double t = static_cast<double>(p + 1) / static_cast<double>(isize + 1);
t = (p > isize / 2) ? 1 - t : t;
t += 0.3;
color = (p == isize / 2) ? targetColor : glm::vec4(t, t, t, 1);
RenderFont(*_fontInfo,
penPosition,
glm::vec4(0.3, 0.3, 0.3, 1),
" |"
);
RenderFontCr(*_fontInfo,
penPosition,
active,
" %5s",
t.first.c_str()
color,
"%s%s",
space.c_str(), incidentTargets.second[p].c_str()
);
for (int k = 0; k < incidentTargets.second[p].size() + 2; k++)
space += " ";
}
#endif
penPosition.y -= _fontInfo->height();
std::map<std::string, bool> activeMap = ImageSequencer::ref().getActiveInstruments();
glm::vec4 firing(0.58 - t, 1 - t, 1 - t, 1);
glm::vec4 notFiring(0.5, 0.5, 0.5, 1);
RenderFontCr(*_fontInfo,
penPosition,
active,
"Active Instruments:"
);
for (auto t : activeMap) {
if (t.second == false) {
RenderFont(*_fontInfo,
penPosition,
glm::vec4(0.3, 0.3, 0.3, 1),
"| |"
);
RenderFontCr(*_fontInfo,
penPosition,
glm::vec4(0.3, 0.3, 0.3, 1),
" %5s",
t.first.c_str()
);
}
else {
RenderFont(*_fontInfo,
penPosition,
glm::vec4(0.3, 0.3, 0.3, 1),
"|"
);
if (t.first == "NH_LORRI") {
RenderFont(*_fontInfo,
penPosition,
firing,
" + "
);
}
RenderFont(*_fontInfo,
penPosition,
glm::vec4(0.3, 0.3, 0.3, 1),
" |"
);
RenderFontCr(*_fontInfo,
penPosition,
active,
" %5s",
t.first.c_str()
);
}
}
}
}
@@ -1723,6 +1734,12 @@ void RenderEngine::renderScreenLog() {
}
}
std::vector<Syncable*> RenderEngine::getSyncables(){
std::vector<Syncable*> syncables = _mainCamera->getSyncables();
syncables.push_back(&_onScreenInformation);
return syncables;
}
void RenderEngine::sortScreenspaceRenderables() {
std::sort(
_screenSpaceRenderables.begin(),

View File

@@ -33,11 +33,18 @@ namespace luascriptfunctions {
*/
int takeScreenshot(lua_State* L) {
int nArguments = lua_gettop(L);
if (nArguments != 0) {
if (nArguments == 0) {
OsEng.renderEngine().takeScreenshot();
return 0;
}
else if (nArguments == 1) {
bool b = lua_toboolean(L, -1) != 0;
OsEng.renderEngine().takeScreenshot(b);
return 0;
}
else {
return luaL_error(L, "Expected %i arguments, got %i", 0, nArguments);
}
OsEng.renderEngine().takeScreenshot();
return 0;
}
/**

View File

@@ -30,6 +30,8 @@
#include <openspace/util/camera.h>
#include <openspace/util/factorymanager.h>
#include <openspace/documentation/verifier.h>
#ifdef WIN32
#define _USE_MATH_DEFINES
#include <math.h>
@@ -50,16 +52,36 @@ namespace {
namespace openspace {
Documentation ScreenSpaceRenderable::Documentation() {
using namespace openspace::documentation;
return {
"Screenspace Renderable",
"core_screenspacerenderable",
{
{
KeyType,
new StringAnnotationVerifier("Must name a valid Screenspace renderable"),
"The type of the Screenspace renderable that is to be created. The "
"available types of Screenspace renderable depend on the configuration of"
"the application and can be written to disk on application startup into "
"the FactoryDocumentation.",
Optional::No
}
}
};
}
ScreenSpaceRenderable* ScreenSpaceRenderable::createFromDictionary(
const ghoul::Dictionary& dictionary)
{
std::string renderableType;
bool success = dictionary.getValue(KeyType, renderableType);
documentation::testSpecificationAndThrow(
Documentation(),
dictionary,
"ScreenSpaceRenderable"
);
if (!success) {
LERROR("ScreenSpaceRenderable did not have key '" << KeyType << "'");
return nullptr;
}
std::string renderableType = dictionary.value<std::string>(KeyType);
auto factory = FactoryManager::ref().factory<ScreenSpaceRenderable>();
ScreenSpaceRenderable* result = factory->create(renderableType, dictionary);

View File

@@ -26,6 +26,8 @@
#include <openspace/util/factorymanager.h>
#include <ghoul/logging/logmanager.h>
#include <openspace/documentation/verifier.h>
namespace {
const std::string _loggerCat = "Ephemeris";
const std::string KeyType = "Type";
@@ -33,6 +35,27 @@ namespace {
namespace openspace {
Documentation Ephemeris::Documentation() {
using namespace openspace::documentation;
return{
"Transformation Translation",
"core_transform_translation",
{
{
KeyType,
new StringAnnotationVerifier("Must name a valid Translation type"),
"The type of translation that is described in this element. "
"The available types of translations depend on the "
"configuration of the application and can be written to disk "
"on application startup into the FactoryDocumentation.",
Optional::No
}
},
Exhaustive::No
};
}
Ephemeris* Ephemeris::createFromDictionary(const ghoul::Dictionary& dictionary) {
if (!dictionary.hasValue<std::string>(KeyType)) {
LERROR("Ephemeris did not have key '" << KeyType << "'");
@@ -52,10 +75,6 @@ Ephemeris* Ephemeris::createFromDictionary(const ghoul::Dictionary& dictionary)
return result;
}
Ephemeris::Ephemeris() {}
Ephemeris::Ephemeris(const ghoul::Dictionary& dictionary) {}
Ephemeris::~Ephemeris() {}
bool Ephemeris::initialize() {

View File

@@ -26,6 +26,8 @@
#include <openspace/util/factorymanager.h>
#include <ghoul/logging/logmanager.h>
#include <openspace/documentation/verifier.h>
namespace {
const std::string _loggerCat = "Rotation";
const std::string KeyType = "Type";
@@ -33,16 +35,31 @@ namespace {
namespace openspace {
Rotation* Rotation::createFromDictionary(const ghoul::Dictionary& dictionary) {
if (!dictionary.hasValue<std::string>(KeyType)) {
LERROR("Ephemeris did not have key '" << KeyType << "'");
return nullptr;
}
Documentation Rotation::Documentation() {
using namespace openspace::documentation;
std::string rotationType;
dictionary.getValue(KeyType, rotationType);
ghoul::TemplateFactory<Rotation>* factory
= FactoryManager::ref().factory<Rotation>();
return {
"Transformation Rotation",
"core_transform_rotation",
{
{
KeyType,
new StringAnnotationVerifier("Must name a valid Rotation type."),
"The type of the rotation that is described in this element. The "
"available types of rotations depend on the configuration of the "
"application and can be written to disk on application startup into the "
"FactoryDocumentation.",
Optional::No
}
}
};
}
Rotation* Rotation::createFromDictionary(const ghoul::Dictionary& dictionary) {
documentation::testSpecificationAndThrow(Documentation(), dictionary, "Rotation");
std::string rotationType = dictionary.value<std::string>(KeyType);
auto factory = FactoryManager::ref().factory<Rotation>();
Rotation* result = factory->create(rotationType, dictionary);
if (result == nullptr) {
LERROR("Failed creating Rotation object of type '" << rotationType << "'");

View File

@@ -26,6 +26,8 @@
#include <openspace/util/factorymanager.h>
#include <ghoul/logging/logmanager.h>
#include <openspace/documentation/verifier.h>
namespace {
const std::string _loggerCat = "Scale";
const std::string KeyType = "Type";
@@ -33,16 +35,34 @@ namespace {
namespace openspace {
Scale* Scale::createFromDictionary(const ghoul::Dictionary& dictionary) {
if (!dictionary.hasValue<std::string>(KeyType)) {
LERROR("Ephemeris did not have key '" << KeyType << "'");
return nullptr;
}
Documentation Scale::Documentation() {
using namespace openspace::documentation;
std::string scaleType;
dictionary.getValue(KeyType, scaleType);
ghoul::TemplateFactory<Scale>* factory
= FactoryManager::ref().factory<Scale>();
return {
"Transformation Scaling",
"core_transform_scaling",
{
{
KeyType,
new StringAnnotationVerifier("Must name a valid Scale type"),
"The type of the scaling that is described in this element. "
"The available types of scaling depend on the configuration "
"of the application and can be written to disk on "
"application startup into the FactoryDocumentation.",
Optional::No
}
},
Exhaustive::No
};
}
Scale* Scale::createFromDictionary(const ghoul::Dictionary& dictionary) {
documentation::testSpecificationAndThrow(Documentation(), dictionary, "Scale");
std::string scaleType = dictionary.value<std::string>(KeyType);
auto factory = FactoryManager::ref().factory<Scale>();
Scale* result = factory->create(scaleType, dictionary);
if (result == nullptr) {
LERROR("Failed creating Scale object of type '" << scaleType << "'");
@@ -52,10 +72,6 @@ Scale* Scale::createFromDictionary(const ghoul::Dictionary& dictionary) {
return result;
}
Scale::Scale() {}
Scale::Scale(const ghoul::Dictionary& dictionary) {}
Scale::~Scale() {}
bool Scale::initialize() {

View File

@@ -55,12 +55,12 @@
#include <modules/onscreengui/include/gui.h>
#endif
#include "scene_doc.inl"
#include "scene_lua.inl"
namespace {
const std::string _loggerCat = "Scene";
const std::string _moduleExtension = ".mod";
const std::string _defaultCommonDirectory = "common";
const std::string _commonModuleToken = "${COMMON_MODULE}";
const std::string KeyCamera = "Camera";
@@ -98,15 +98,23 @@ void Scene::update(const UpdateData& data) {
OsEng.interactionHandler().setInteractionMode("Orbital");
// After loading the scene, the keyboard bindings have been set
const std::string KeyboardShortcutsType =
ConfigurationManager::KeyKeyboardShortcuts + "." +
ConfigurationManager::PartType;
const std::string KeyboardShortcutsFile =
ConfigurationManager::KeyKeyboardShortcuts + "." +
ConfigurationManager::PartFile;
std::string type;
std::string file;
bool hasType = OsEng.configurationManager().getValue(
ConfigurationManager::KeyKeyboardShortcutsType, type
KeyboardShortcutsType, type
);
bool hasFile = OsEng.configurationManager().getValue(
ConfigurationManager::KeyKeyboardShortcutsFile, file
KeyboardShortcutsFile, file
);
if (hasType && hasFile) {
@@ -189,6 +197,14 @@ bool Scene::loadSceneInternal(const std::string& sceneDescriptionFilePath) {
state
);
// Perform testing against the documentation/specification
openspace::documentation::testSpecificationAndThrow(
Scene::Documentation(),
dictionary,
"Scene"
);
_graph.loadFromFile(sceneDescriptionFilePath);
// Initialize all nodes
@@ -213,7 +229,7 @@ bool Scene::loadSceneInternal(const std::string& sceneDescriptionFilePath) {
glm::dvec3(0),
glm::dmat3(1),
1,
Time::ref().currentTime() });
Time::ref().j2000Seconds() });
}
catch (const ghoul::RuntimeError& e) {
LERRORC(e.component, e.message);
@@ -230,13 +246,21 @@ bool Scene::loadSceneInternal(const std::string& sceneDescriptionFilePath) {
}
// If a PropertyDocumentationFile was specified, generate it now
const bool hasType = OsEng.configurationManager().hasKey(ConfigurationManager::KeyPropertyDocumentationType);
const bool hasFile = OsEng.configurationManager().hasKey(ConfigurationManager::KeyPropertyDocumentationFile);
const std::string KeyPropertyDocumentationType =
ConfigurationManager::KeyPropertyDocumentation + '.' +
ConfigurationManager::PartType;
const std::string KeyPropertyDocumentationFile =
ConfigurationManager::KeyPropertyDocumentation + '.' +
ConfigurationManager::PartFile;
const bool hasType = OsEng.configurationManager().hasKey(KeyPropertyDocumentationType);
const bool hasFile = OsEng.configurationManager().hasKey(KeyPropertyDocumentationFile);
if (hasType && hasFile) {
std::string propertyDocumentationType;
OsEng.configurationManager().getValue(ConfigurationManager::KeyPropertyDocumentationType, propertyDocumentationType);
OsEng.configurationManager().getValue(KeyPropertyDocumentationType, propertyDocumentationType);
std::string propertyDocumentationFile;
OsEng.configurationManager().getValue(ConfigurationManager::KeyPropertyDocumentationFile, propertyDocumentationFile);
OsEng.configurationManager().getValue(KeyPropertyDocumentationFile, propertyDocumentationFile);
propertyDocumentationFile = absPath(propertyDocumentationFile);
writePropertyDocumentation(propertyDocumentationFile, propertyDocumentationType);
@@ -414,13 +438,11 @@ SceneGraph& Scene::sceneGraph() {
}
void Scene::writePropertyDocumentation(const std::string& filename, const std::string& type) {
LDEBUG("Writing documentation for properties");
if (type == "text") {
LDEBUG("Writing documentation for properties");
std::ofstream file(filename);
if (!file.good()) {
LERROR("Could not open file '" << filename << "' for writing property documentation");
return;
}
std::ofstream file;
file.exceptions(~std::ofstream::goodbit);
file.open(filename);
using properties::Property;
for (SceneGraphNode* node : _graph.nodes()) {
@@ -429,13 +451,100 @@ void Scene::writePropertyDocumentation(const std::string& filename, const std::s
file << node->name() << std::endl;
for (Property* p : properties) {
file << p->fullyQualifiedIdentifier() << ": " << p->guiName() << std::endl;
file << p->fullyQualifiedIdentifier() << ": " <<
p->guiName() << std::endl;
}
file << std::endl;
}
}
}
else if (type == "html") {
std::ofstream file;
file.exceptions(~std::ofstream::goodbit);
file.open(filename);
#ifdef JSON
// Create JSON
std::function<std::string(properties::PropertyOwner*)> createJson =
[&createJson](properties::PropertyOwner* owner) -> std::string
{
std::stringstream json;
json << "{";
json << "\"name\": \"" << owner->name() << "\",";
json << "\"properties\": [";
for (properties::Property* p : owner->properties()) {
json << "{";
json << "\"id\": \"" << p->identifier() << "\",";
json << "\"type\": \"" << p->className() << "\",";
json << "\"fullyQualifiedId\": \"" << p->fullyQualifiedIdentifier() << "\",";
json << "\"guiName\": \"" << p->guiName() << "\",";
json << "},";
}
json << "],";
json << "\"propertyOwner\": [";
for (properties::PropertyOwner* o : owner->propertySubOwners()) {
json << createJson(o);
}
json << "],";
json << "},";
return json.str();
};
std::stringstream json;
json << "[";
for (SceneGraphNode* node : _graph.nodes()) {
json << createJson(node);
}
json << "]";
std::string jsonText = json.str();
#else
std::stringstream html;
html << "<html>\n"
<< "\t<head>\n"
<< "\t\t<title>Properties</title>\n"
<< "\t</head>\n"
<< "<body>\n"
<< "<table cellpadding=3 cellspacing=0 border=1>\n"
<< "\t<caption>Properties</caption>\n\n"
<< "\t<thead>\n"
<< "\t\t<tr>\n"
<< "\t\t\t<th>ID</th>\n"
<< "\t\t\t<th>Type</th>\n"
<< "\t\t\t<th>Description</th>\n"
<< "\t\t</tr>\n"
<< "\t</thead>\n"
<< "\t<tbody>\n";
for (SceneGraphNode* node : _graph.nodes()) {
for (properties::Property* p : node->propertiesRecursive()) {
html << "\t\t<tr>\n"
<< "\t\t\t<td>" << p->fullyQualifiedIdentifier() << "</td>\n"
<< "\t\t\t<td>" << p->className() << "</td>\n"
<< "\t\t\t<td>" << p->guiName() << "</td>\n"
<< "\t\t</tr>\n";
}
if (!node->propertiesRecursive().empty()) {
html << "\t<tr><td style=\"line-height: 10px;\" colspan=3></td></tr>\n";
}
}
html << "\t</tbody>\n"
<< "</table>\n"
<< "</html>;";
file << html.str();
#endif
}
else
LERROR("Undefined type '" << type << "' for Property documentation");
}
@@ -455,6 +564,7 @@ scripting::LuaLibrary Scene::luaLibrary() {
{
"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 "

95
src/scene/scene_doc.inl Normal file
View File

@@ -0,0 +1,95 @@
/*****************************************************************************************
* *
* 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 <openspace/documentation/verifier.h>
namespace openspace {
Documentation Scene::Documentation() {
using namespace documentation;
return {
"Scene Description",
{
{
"ScenePath",
new StringVerifier,
"The path to the base directory of the scene. The path is considered "
"relative to the location of the scene description file.",
Optional::Yes
},
{
"CommonFolder",
new StringAnnotationVerifier("A valid scene module folder"),
"The path to the common folder that is loaded and will be bound to the "
"${COMMON_MODULE} path token so that assets can be reused easily.",
Optional::Yes
},
{
"Camera",
new TableVerifier({
{
"Focus",
new StringAnnotationVerifier("A valid object in the scene"),
"The initial focus node of the camera, i.e., the node around which "
"the interaction will be performed."
},
{
"Position",
new DoubleVector3Verifier,
"The initial camera positive relative to the focus object.",
Optional::Yes
},
{
"Rotation",
new DoubleVector4Verifier,
"The initial camera rotation expressed as a quaternion.",
Optional::Yes
}
}),
"Definitions of the camera starting parameters, such as focus, location, and "
"orientation.",
Optional::Yes
},
{
"Modules",
new TableVerifier({
{ "*", new StringAnnotationVerifier(
"Loadable module folders. This means that they either have to point "
"to a folder that contains a ModuleFile or a folder which contains "
"other folders that eventually contain ModuleFile. This second "
"recursive approach is useful for grouping modules into logical "
"units."
)}
}),
"This is the list of modules that will be loaded into the initial scene. The "
"values in this table have to correspond to folders relative to the "
"ScenePath key. The order in which the modules are loaded is the same as the "
"order in which they are specified in this table."
}
}
};
}
} // namespace openspace

View File

@@ -310,6 +310,7 @@ bool SceneGraph::loadFromFile(const std::string& sceneDescription) {
element.getValue(SceneGraphNode::KeyParentName, parentName);
FileSys.setCurrentDirectory(modulePath);
LDEBUGC("Create from dictionary", "Node name: " << nodeName << " Parent name:" << parentName << " Path: " << modulePath);
SceneGraphNode* node = SceneGraphNode::createFromDictionary(element);
if (node == nullptr) {
LERROR("Error loading SceneGraphNode '" << nodeName << "' in module '" << moduleName << "'");
@@ -344,7 +345,17 @@ bool SceneGraph::loadFromFile(const std::string& sceneDescription) {
};
for (const ModuleInformation& i : moduleDictionaries) {
addModule(i);
try {
LINFO("Adding module: " << i.moduleName);
addModule(i);
}
catch (const documentation::SpecificationError& specError) {
LERROR("Error loading module: " << i.moduleName);
LERRORC(specError.component, specError.message);
for (const auto& offense : specError.result.offenses) {
LERRORC(offense.offender, std::to_string(offense.reason));
}
}
}
}
// ghoul::lua::destroyLuaState(state);

View File

@@ -24,6 +24,9 @@
// open space includes
#include <openspace/scene/scenegraphnode.h>
#include <openspace/documentation/documentation.h>
#include <openspace/query/query.h>
#include <openspace/util/spicemanager.h>
#include <openspace/util/time.h>
@@ -46,6 +49,8 @@
#include <cctype>
#include <chrono>
#include "scenegraphnode_doc.inl"
namespace {
const std::string _loggerCat = "SceneGraphNode";
const std::string KeyRenderable = "Renderable";
@@ -63,8 +68,13 @@ const std::string SceneGraphNode::KeyName = "Name";
const std::string SceneGraphNode::KeyParentName = "Parent";
const std::string SceneGraphNode::KeyDependencies = "Dependencies";
SceneGraphNode* SceneGraphNode::createFromDictionary(const ghoul::Dictionary& dictionary)
{
SceneGraphNode* SceneGraphNode::createFromDictionary(const ghoul::Dictionary& dictionary){
openspace::documentation::testSpecificationAndThrow(
SceneGraphNode::Documentation(),
dictionary,
"SceneGraphNode"
);
SceneGraphNode* result = new SceneGraphNode;
if (!dictionary.hasValue<std::string>(KeyName)) {
@@ -343,12 +353,20 @@ void SceneGraphNode::render(const RenderData& data, RendererTasks& tasks) {
data.camera,
thisPositionPSC,
data.doPerformanceMeasurement,
data.renderBinMask,
_worldPositionCached,
_worldRotationCached,
_worldScaleCached};
_performanceRecord.renderTime = 0;
if (_renderableVisible && _renderable->isVisible() && _renderable->isReady() && _renderable->isEnabled()) {
bool visible = _renderableVisible &&
_renderable->isVisible() &&
_renderable->isReady() &&
_renderable->isEnabled() &&
_renderable->matchesRenderBinMask(data.renderBinMask);
if (visible) {
if (data.doPerformanceMeasurement) {
glFinish();
auto start = std::chrono::high_resolution_clock::now();
@@ -371,7 +389,7 @@ void SceneGraphNode::render(const RenderData& data, RendererTasks& tasks) {
void SceneGraphNode::postRender(const RenderData& data) {
const psc thisPosition = psc::CreatePowerScaledCoordinate(_worldPositionCached.x, _worldPositionCached.y, _worldPositionCached.z);
RenderData newData = { data.camera, thisPosition, data.doPerformanceMeasurement, _worldPositionCached};
RenderData newData = { data.camera, thisPosition, data.doPerformanceMeasurement, data.renderBinMask, _worldPositionCached};
_performanceRecord.renderTime = 0;
if (_renderableVisible && _renderable->isVisible() && _renderable->isReady() && _renderable->isEnabled()) {
@@ -584,7 +602,7 @@ SceneGraphNode* SceneGraphNode::childNode(const std::string& name)
void SceneGraphNode::updateCamera(Camera* camera) const{
psc origin = worldPosition();
psc origin(worldPosition());
//int i = 0;
// the camera position

View File

@@ -0,0 +1,102 @@
/*****************************************************************************************
* *
* 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 <openspace/documentation/verifier.h>
namespace openspace {
Documentation SceneGraphNode::Documentation() {
using namespace documentation;
return {
"Scenegraph Node",
{
{
"Name",
new StringVerifier,
"The name of this scenegraph node. This name must be unique among all scene "
"graph nodes that are loaded in a specific scene. If a duplicate is detected "
"the loading of the node will fail, as will all childing that depend on the "
"node."
},
{
"Parent",
new StringAnnotationVerifier(
"Must be a name for another scenegraph node, or 'Root'"
),
"This names the parent of the currently specified scenegraph node. The "
"parent must not have been defined earlier, but must exist at loading time, "
"or the scenegraph node creation will fail. A special parent 'Root' is "
"available that denotes the root of the scenegraph."
},
{
"Renderable",
new ReferencingVerifier("renderable"),
"The renderable that is to be created for this scenegraph node. A renderable "
"is a component of a scenegraph node that will lead to some visual result on "
"the screen. The specifics heavily depend on the 'Type' of the renderable. "
"If no Renderable is specified, this scenegraph node is an internal node and "
"can be used for either group children, or apply common transformations to a "
"group of children.",
Optional::Yes
},
{
"Transform",
new TableVerifier({
{
"Translation",
new ReferencingVerifier("core_transform_translation"),
"This node describes a translation that is applied to the scenegraph "
"node and all its children. Depending on the 'Type' of the "
"translation, this can either be a static translation or a "
"time-varying one.",
Optional::Yes
},
{
"Rotation",
new ReferencingVerifier("core_transform_rotation"),
"This nodes describes a rotation that is applied to the scenegraph "
"node and all its children. Depending on the 'Type' of the rotation, "
"this can either be a static rotation or a time-varying one.",
Optional::Yes
},
{
"Scale",
new ReferencingVerifier("core_transform_scaling"),
"This node describes a scaling that is applied to the scenegraph "
"node and all its children. Depending on the 'Type' of the scaling, "
"this can either be a static scaling or a time-varying one.",
Optional::Yes
}
}),
"This describes a set of transformations that are applied to this scenegraph "
"node and all of its children. There are only three possible values "
"corresponding to a 'Translation', a 'Rotation', and a 'Scale'.",
Optional::Yes
},
}
};
}
} // namespace openspace

View File

@@ -27,6 +27,7 @@
#include <ghoul/filesystem/filesystem.h>
#include <ghoul/logging/logmanager.h>
#include <ghoul/lua/lua_helper.h>
#include <ghoul/misc/exception.h>
#include <openspace/engine/configurationmanager.h>
#include <openspace/engine/openspaceengine.h>
@@ -51,7 +52,6 @@ namespace {
//const lua_CFunction _printFunctionReplacement = luascriptfunctions::printInfo;
const int _setTableOffset = -3; // -1 (top) -1 (first argument) -1 (second argument)
}
void ScriptEngine::initialize() {
@@ -479,41 +479,36 @@ std::vector<std::string> ScriptEngine::allLuaFunctions() const {
return result;
}
bool ScriptEngine::writeDocumentation(const std::string& filename, const std::string& type) const {
if (type == "text") {
// The additional space between the longest function name and the descriptions
LDEBUG("Writing Lua documentation of type '" << type <<
"' to file '" << filename << "'");
std::ofstream file(filename);
if (!file.good()) {
LERROR("Could not open file '" << filename << "' for writing documentation");
return false;
void ScriptEngine::writeDocumentation(const std::string& filename, const std::string& type) const {
auto concatenate = [](std::string library, std::string function) {
std::string total = "openspace.";
if (!library.empty()) {
total += std::move(library) + ".";
}
total += std::move(function);
return total;
};
auto concatenate = [](std::string library, std::string function) {
std::string total = "openspace.";
if (!library.empty())
total += std::move(library) + ".";
total += std::move(function);
return total;
};
LDEBUG("Writing Lua documentation of type '" << type <<
"' to file '" << filename << "'");
if (type == "text") {
// Settings
const unsigned int lineWidth = 80;
static const std::string whitespace = " \t";
static const std::string padding = " ";
const bool commandListArguments = true;
// The additional space between the longest function name and the descriptions
std::ofstream file;
file.exceptions(~std::ofstream::goodbit);
file.open(filename);
file << "Available commands:\n";
// Now write out the functions
for (const LuaLibrary& library : _registeredLibraries) {
for (const LuaLibrary::Function& function : library.functions) {
std::string functionName = concatenate(library.name, function.name);
file << padding << functionName;
if (commandListArguments)
file << "(" << function.argumentText << ")";
file << std::endl;
for (const LuaLibrary& l : _registeredLibraries) {
for (const LuaLibrary::Function& f : l.functions) {
std::string name = concatenate(l.name, f.name);
file << padding << name << "(" << f.argumentText << ")" << std::endl;
}
}
file << std::endl;
@@ -521,24 +516,32 @@ bool ScriptEngine::writeDocumentation(const std::string& filename, const std::st
// Now write out the functions definitions
for (const LuaLibrary& library : _registeredLibraries) {
for (const LuaLibrary::Function& function : library.functions) {
std::string functionName = concatenate(library.name, function.name);
file << functionName << "(" << function.argumentText << "):" << std::endl;
std::string name = concatenate(library.name, function.name);
file << name << "(" << function.argumentText << "):" << std::endl;
std::string remainingHelptext = function.helpText;
// @CLEANUP This needs to become a bit prettier ---abock
while (!remainingHelptext.empty()) {
const auto length = remainingHelptext.length();
const auto paddingLength = padding.length();
const size_t length = remainingHelptext.length();
const size_t paddingLength = padding.length();
if ((length + paddingLength) > lineWidth) {
auto lastSpace = remainingHelptext.find_last_of(whitespace, lineWidth - 1 - paddingLength);
if (lastSpace == remainingHelptext.npos)
size_t lastSpace = remainingHelptext.find_last_of(
whitespace,
lineWidth - 1 - paddingLength
);
if (lastSpace == remainingHelptext.npos) {
lastSpace = lineWidth;
file << padding << remainingHelptext.substr(0, lastSpace) << std::endl;
auto firstNotSpace = remainingHelptext.find_first_not_of(whitespace, lastSpace);
if (firstNotSpace == remainingHelptext.npos)
}
file << padding << remainingHelptext.substr(0, lastSpace) << '\n';
size_t firstNotSpace = remainingHelptext.find_first_not_of(
whitespace,
lastSpace
);
if (firstNotSpace == remainingHelptext.npos) {
firstNotSpace = lastSpace;
}
remainingHelptext = remainingHelptext.substr(firstNotSpace);
}
else {
@@ -549,27 +552,115 @@ bool ScriptEngine::writeDocumentation(const std::string& filename, const std::st
file << std::endl;
}
}
return true;
}
else if (type == "html") {
std::ofstream file;
file.exceptions(~std::ofstream::goodbit);
file.open(filename);
#ifdef JSON
// Create JSON
std::stringstream json;
json << "[";
for (const LuaLibrary& l : _registeredLibraries) {
json << "{";
json << "\"library\": \"" << l.name << "\",";
json << "\"functions\": [";
for (const LuaLibrary::Function& f : l.functions) {
json << "{";
json << "\"name\": \"" << f.name << "\", ";
json << "\"arguments\": \"" << f.argumentText << "\", ";
json << "\"help\": \"" << f.helpText << "\"";
json << "},";
}
json << "]},";
}
json << "]";
std::string jsonText = json.str();
#else
std::stringstream html;
html << "<html>\n"
<< "\t<head>\n"
<< "\t\t<title>Script Log</title>\n"
<< "\t</head>\n"
<< "<body>\n"
<< "<table cellpadding=3 cellspacing=0 border=1>\n"
<< "\t<caption>Script Log</caption>\n\n"
<< "\t<thead>\n"
<< "\t\t<tr>\n"
<< "\t\t\t<th rowspan=2>Library</th>\n"
<< "\t\t\t<th colspan=3>Functions</th>\n"
<< "\t\t</tr>\n"
<< "\t\t<tr>\n"
<< "\t\t\t<th>Name</th>\n"
<< "\t\t\t<th>Arguments</th>\n"
<< "\t\t\t<th>Help</th>\n"
<< "\t\t</tr>\n"
<< "\t</thead>\n"
<< "\t<tbody>\n";
for (const LuaLibrary& l : _registeredLibraries) {
html << "\t<tr>\n";
if (l.name.empty()) {
html << "\t\t<td>openspace</td>\n";
}
else {
html << "\t\t<td>openspace." << l.name << "</td>\n";
}
html << "\t\t<td></td><td></td><td></td>\n"
<< "\t\</tr>";
for (const LuaLibrary::Function& f : l.functions) {
html << "\t<tr>\n"
<< "\t\t<td></td>\n"
<< "\t\t<td>" << f.name << "</td>\n"
<< "\t\t<td>" << f.argumentText << "</td>\n"
<< "\t\t<td>" << f.helpText << "</td>\n"
<< "\t</tr>\n";
}
html << "\t<tr><td style=\"line-height: 10px;\" colspan=4></td></tr>\n";
}
html << "\t</tbody>\n"
<< "</table>\n"
<< "</html>";
file << html.str();
#endif
}
else {
LERROR("Undefined type '" << type << "' for Lua documentation");
return false;
throw ghoul::RuntimeError("Undefined type '" + type + "' for Lua documentation");
}
}
bool ScriptEngine::writeLog(const std::string& script) {
const std::string KeyScriptLogType =
ConfigurationManager::KeyScriptLog + '.' + ConfigurationManager::PartType;
const std::string KeyScriptLogFile =
ConfigurationManager::KeyScriptLog + '.' + ConfigurationManager::PartFile;
// Check that logging is enabled and initialize if necessary
if (!_logFileExists) {
// If a ScriptLogFile was specified, generate it now
const bool hasType = OsEng.configurationManager()
.hasKey(ConfigurationManager::KeyScriptLogType);
.hasKey(KeyScriptLogType);
const bool hasFile = OsEng.configurationManager()
.hasKey(ConfigurationManager::KeyScriptLogFile);
.hasKey(KeyScriptLogFile);
if (hasType && hasFile) {
OsEng.configurationManager()
.getValue(ConfigurationManager::KeyScriptLogType, _logType);
.getValue(KeyScriptLogType, _logType);
OsEng.configurationManager()
.getValue(ConfigurationManager::KeyScriptLogFile, _logFilename);
.getValue(KeyScriptLogFile, _logFilename);
_logFilename = absPath(_logFilename);
_logFileExists = true;
@@ -588,8 +679,8 @@ bool ScriptEngine::writeLog(const std::string& script) {
}
} else {
LDEBUG("No script log specified in 'openspace.cfg.' To log, set '"
<< ConfigurationManager::KeyScriptLogType << " and "
<< ConfigurationManager::KeyScriptLogFile
<< KeyScriptLogType << " and "
<< KeyScriptLogFile
<< " in configuration table.");
_logScripts = false;
return false;
@@ -616,51 +707,16 @@ bool ScriptEngine::writeLog(const std::string& script) {
return true;
}
void ScriptEngine::serialize(SyncBuffer* syncBuffer){
syncBuffer->encode(_currentSyncedScript);
_currentSyncedScript.clear();
}
void ScriptEngine::deserialize(SyncBuffer* syncBuffer){
syncBuffer->decode(_currentSyncedScript);
if (!_currentSyncedScript.empty()){
_mutex.lock();
_receivedScripts.push_back(_currentSyncedScript);
_mutex.unlock();
}
}
void ScriptEngine::postSynchronizationPreDraw() {
std::vector<std::string> scripts;
void ScriptEngine::presync(bool isMaster) {
if (!isMaster) return;
_mutex.lock();
scripts.assign(_receivedScripts.begin(), _receivedScripts.end());
_receivedScripts.clear();
_mutex.unlock();
while (!scripts.empty()) {
try {
runScript(scripts.back());
}
catch (const ghoul::RuntimeError& e) {
LERRORC(e.component, e.message);
}
scripts.pop_back();
}
}
void ScriptEngine::preSynchronization() {
_mutex.lock();
if (!_queuedScripts.empty()){
if (!_queuedScripts.empty()) {
_currentSyncedScript = _queuedScripts.back().first;
bool remoteScripting = _queuedScripts.back().second;
//Not really a received script but the master also needs to run the script...
_receivedScripts.push_back(_currentSyncedScript);
_queuedScripts.pop_back();
@@ -670,8 +726,43 @@ void ScriptEngine::preSynchronization() {
}
}
_mutex.unlock();
}
void ScriptEngine::encode(SyncBuffer* syncBuffer) {
syncBuffer->encode(_currentSyncedScript);
_currentSyncedScript.clear();
}
void ScriptEngine::decode(SyncBuffer* syncBuffer) {
syncBuffer->decode(_currentSyncedScript);
if (!_currentSyncedScript.empty()) {
_mutex.lock();
_receivedScripts.push_back(_currentSyncedScript);
_mutex.unlock();
}
}
void ScriptEngine::postsync(bool isMaster) {
std::vector<std::string> scripts;
_mutex.lock();
scripts.assign(_receivedScripts.begin(), _receivedScripts.end());
_receivedScripts.clear();
_mutex.unlock();
while (!scripts.empty()) {
try {
runScript(scripts.back());
}
catch (const ghoul::RuntimeError& e) {
LERRORC(e.component, e.message);
}
scripts.pop_back();
}
}
void ScriptEngine::queueScript(const std::string &script, ScriptEngine::RemoteScripting remoteScripting){

View File

@@ -0,0 +1,197 @@
/*****************************************************************************************
* *
* 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 <openspace/scripting/scriptscheduler.h>
#include <openspace/engine/openspaceengine.h>
#include <openspace/scripting/scriptengine.h>
#include <openspace/util/spicemanager.h> // parse time
#include <ghoul/logging/logmanager.h>
#include <ghoul/filesystem/filesystem>
namespace openspace {
namespace scripting {
namespace {
const std::string _loggerCat = "ScriptScheduler";
const std::string KEY_TIME = "Time";
const std::string KEY_FORWARD_SCRIPT = "ReversibleLuaScript.Forward";
const std::string KEY_BACKWARD_SCRIPT = "ReversibleLuaScript.Backward";
}
ScheduledScript::ScheduledScript(const ghoul::Dictionary& dict)
: ScheduledScript() // default init first
{
std::string timeStr;
if (dict.getValue(KEY_TIME, timeStr)) {
time = SpiceManager::ref().ephemerisTimeFromDate(timeStr);
if (!dict.getValue(KEY_FORWARD_SCRIPT, script.forwardScript)) {
LERROR("Unable to read " << KEY_FORWARD_SCRIPT);
}
if (!dict.getValue(KEY_BACKWARD_SCRIPT, script.backwardScript)) {
LERROR("Unable to read " << KEY_BACKWARD_SCRIPT);
}
}
else {
LERROR("Unable to read " << KEY_TIME);
}
}
bool ScheduledScript::CompareByTime(const ScheduledScript& s1, const ScheduledScript& s2){
return s1.time < s2.time;
}
void ScriptScheduler::loadScripts(const std::string& filepath, lua_State* L) {
ghoul::Dictionary timedScriptsDict;
try {
ghoul::lua::loadDictionaryFromFile(absPath(filepath), timedScriptsDict, L);
}
catch (const ghoul::RuntimeError& e) {
LERROR(e.what());
return;
}
loadScripts(timedScriptsDict);
}
void ScriptScheduler::loadScripts(const ghoul::Dictionary& dict) {
for (size_t i = 0; i < dict.size(); ++i) {
std::string id = std::to_string(i + 1);
const ghoul::Dictionary& timedScriptDict = dict.value<ghoul::Dictionary>(id);
_scheduledScripts.push_back(ScheduledScript(timedScriptDict));
}
// Sort scripts by time
std::stable_sort(_scheduledScripts.begin(), _scheduledScripts.end(), &ScheduledScript::CompareByTime);
// Ensure _currentIndex and _currentTime is accurate after new scripts was added
double lastTime = _currentTime;
rewind();
progressTo(lastTime);
}
void ScriptScheduler::rewind() {
_currentIndex = 0;
_currentTime = -DBL_MAX;
}
void ScriptScheduler::clearSchedule() {
rewind();
_scheduledScripts.clear();
}
std::queue<std::string> ScriptScheduler::progressTo(double newTime) {
std::queue<std::string> triggeredScripts;
if (newTime > _currentTime) {
while(_currentIndex < _scheduledScripts.size() && _scheduledScripts[_currentIndex].time <= newTime){
triggeredScripts.push(_scheduledScripts[_currentIndex].script.forwardScript);
_currentIndex++;
}
}
else {
while (0 < _currentIndex && _scheduledScripts[_currentIndex - 1].time > newTime) {
triggeredScripts.push(_scheduledScripts[_currentIndex - 1].script.backwardScript);
_currentIndex--;
}
}
_currentTime = newTime;
return triggeredScripts;
}
std::queue<std::string> ScriptScheduler::progressTo(const std::string& timeStr) {
return std::move(progressTo(SpiceManager::ref().ephemerisTimeFromDate(timeStr)));
}
double ScriptScheduler::currentTime() const {
return _currentTime;
};
const std::vector<ScheduledScript>& ScriptScheduler::allScripts() const {
return _scheduledScripts;
};
/////////////////////////////////////////////////////////////////////
// Lua library functions //
/////////////////////////////////////////////////////////////////////
namespace luascriptfunctions {
int loadTimedScripts(lua_State* L) {
using ghoul::lua::luaTypeToString;
int nArguments = lua_gettop(L);
if (nArguments != 1)
return luaL_error(L, "Expected %i arguments, got %i", 1, nArguments);
std::string missionFileName = luaL_checkstring(L, -1);
if (missionFileName.empty()) {
return luaL_error(L, "filepath string is empty");
}
OsEng.scriptScheduler().loadScripts(missionFileName, L);
}
int clear(lua_State* L) {
using ghoul::lua::luaTypeToString;
int nArguments = lua_gettop(L);
if (nArguments != 0)
return luaL_error(L, "Expected %i arguments, got %i", 0, nArguments);
OsEng.scriptScheduler().clearSchedule();
}
} // namespace luascriptfunction
LuaLibrary ScriptScheduler::luaLibrary() {
return {
"scriptScheduler",
{
{
"load",
&luascriptfunctions::loadTimedScripts,
"string",
"Load timed scripts from file"
},
{
"clear",
&luascriptfunctions::clear,
"",
"clears all scheduled scripts"
},
}
};
}
} // namespace scripting
} // namespace openspace

View File

@@ -50,10 +50,11 @@ namespace openspace {
: _maxFov(0.f)
, _focusPosition()
{
_scaling.local = glm::vec2(1.f, 0.f);
_position.local = Vec3(1.0, 1.0, 1.0);
_scaling = glm::vec2(1.f, 0.f);
_position = Vec3(1.0, 1.0, 1.0);
Vec3 eulerAngles(1.0, 1.0, 1.0);
_rotation.local = Quat(eulerAngles);
_rotation = Quat(eulerAngles);
}
Camera::Camera(const Camera& o)
@@ -61,9 +62,9 @@ namespace openspace {
, _focusPosition(o._focusPosition)
, _cachedViewDirection(o._cachedViewDirection)
, _cachedLookupVector(o._cachedLookupVector)
, _position(o._position)
, _rotation(o._rotation)
, _scaling(o._scaling)
, _position(o._position)
, _maxFov(o._maxFov)
{ }
@@ -72,7 +73,7 @@ namespace openspace {
// Mutators
void Camera::setPositionVec3(Vec3 pos) {
std::lock_guard<std::mutex> _lock(_mutex);
_position.local = pos;
_position = pos;
_cachedCombinedViewMatrix.isDirty = true;
}
@@ -84,7 +85,7 @@ namespace openspace {
void Camera::setRotation(Quat rotation) {
std::lock_guard<std::mutex> _lock(_mutex);
_rotation.local = rotation;
_rotation = rotation;
_cachedViewDirection.isDirty = true;
_cachedLookupVector.isDirty = true;
_cachedViewRotationMatrix.isDirty = true;
@@ -93,7 +94,7 @@ namespace openspace {
void Camera::setScaling(glm::vec2 scaling) {
std::lock_guard<std::mutex> _lock(_mutex);
_scaling.local = std::move(scaling);
_scaling = std::move(scaling);
}
void Camera::setMaxFov(float fov) {
@@ -105,7 +106,7 @@ namespace openspace {
// Relative mutators
void Camera::rotate(Quat rotation) {
std::lock_guard<std::mutex> _lock(_mutex);
_rotation.local = rotation * _rotation.local;
_rotation = rotation * (glm::dquat)_rotation;
_cachedViewDirection.isDirty = true;
_cachedLookupVector.isDirty = true;
@@ -115,11 +116,11 @@ namespace openspace {
// Accessors
const Camera::Vec3& Camera::positionVec3() const {
return _position.synced;
return _position;
}
const Camera::Vec3& Camera::unsynchedPositionVec3() const {
return _position.local;
return _position;
}
const Camera::Vec3& Camera::focusPositionVec3() const {
@@ -129,7 +130,7 @@ namespace openspace {
const Camera::Vec3& Camera::viewDirectionWorldSpace() const {
if (_cachedViewDirection.isDirty) {
_cachedViewDirection.datum =
_rotation.synced * Vec3(_VIEW_DIRECTION_CAMERA_SPACE);
(glm::dquat)_rotation * Vec3(_VIEW_DIRECTION_CAMERA_SPACE);
_cachedViewDirection.datum = glm::normalize(_cachedViewDirection.datum);
_cachedViewDirection.isDirty = true;
}
@@ -143,7 +144,7 @@ namespace openspace {
const Camera::Vec3& Camera::lookUpVectorWorldSpace() const {
if (_cachedLookupVector.isDirty) {
_cachedLookupVector.datum =
_rotation.synced * Vec3(_LOOKUP_VECTOR_CAMERA_SPACE);
(glm::dquat)_rotation * Vec3(_LOOKUP_VECTOR_CAMERA_SPACE);
_cachedLookupVector.datum = glm::normalize(_cachedLookupVector.datum);
_cachedLookupVector.isDirty = true;
}
@@ -151,7 +152,7 @@ namespace openspace {
}
const glm::vec2& Camera::scaling() const {
return _scaling.synced;
return _scaling;
}
float Camera::maxFov() const {
@@ -168,19 +169,19 @@ namespace openspace {
const Camera::Mat4& Camera::viewRotationMatrix() const {
if (_cachedViewRotationMatrix.isDirty) {
_cachedViewRotationMatrix.datum = glm::mat4_cast(glm::inverse(_rotation.synced));
_cachedViewRotationMatrix.datum = glm::mat4_cast(glm::inverse((glm::dquat)_rotation));
}
return _cachedViewRotationMatrix.datum;
}
const Camera::Quat& Camera::rotationQuaternion() const {
return _rotation.synced;
return _rotation;
}
const Camera::Mat4& Camera::combinedViewMatrix() const {
if (_cachedCombinedViewMatrix.isDirty) {
Mat4 cameraTranslation =
glm::inverse(glm::translate(Mat4(1.0), _position.synced));
glm::inverse(glm::translate(Mat4(1.0), (Vec3)_position));
_cachedCombinedViewMatrix.datum =
Mat4(sgctInternal.viewMatrix()) *
Mat4(viewRotationMatrix()) *
@@ -190,30 +191,7 @@ namespace openspace {
return _cachedCombinedViewMatrix.datum;
}
// Synchronization
void Camera::serialize(SyncBuffer* syncBuffer) {
std::lock_guard<std::mutex> _lock(_mutex);
_rotation.serialize(syncBuffer);
_position.serialize(syncBuffer);
_scaling.serialize(syncBuffer);
}
void Camera::deserialize(SyncBuffer* syncBuffer) {
std::lock_guard<std::mutex> _lock(_mutex);
_rotation.deserialize(syncBuffer);
_position.deserialize(syncBuffer);
_scaling.deserialize(syncBuffer);
}
void Camera::postSynchronizationPreDraw() {
std::lock_guard<std::mutex> _lock(_mutex);
_rotation.postSynchronizationPreDraw();
_position.postSynchronizationPreDraw();
_scaling.postSynchronizationPreDraw();
void Camera::invalidateCache() {
_cachedViewDirection.isDirty = true;
_cachedLookupVector.isDirty = true;
_cachedViewRotationMatrix.isDirty = true;
@@ -237,14 +215,6 @@ namespace openspace {
setRotation(q);
}
void Camera::preSynchronization() {
std::lock_guard<std::mutex> _lock(_mutex);
_rotation.preSynchronization();
_position.preSynchronization();
_scaling.preSynchronization();
}
//////////////////////////////////////////////////////////////////////////////////////
// SGCT INTERNAL //
//////////////////////////////////////////////////////////////////////////////////////
@@ -287,7 +257,7 @@ namespace openspace {
// Deprecated
void Camera::setPosition(psc pos) {
std::lock_guard<std::mutex> _lock(_mutex);
_position.local = pos.dvec3();
_position = pos.dvec3();
}
void Camera::setFocusPosition(psc pos) {
@@ -296,11 +266,11 @@ namespace openspace {
}
psc Camera::position() const {
return psc(_position.synced);
return psc((Vec3)_position);
}
psc Camera::unsynchedPosition() const {
return psc(_position.local);
return psc((Vec3)_position);
}
psc Camera::focusPosition() const {
@@ -318,4 +288,9 @@ namespace openspace {
const glm::mat4& Camera::viewProjectionMatrix() const {
return sgctInternal.viewProjectionMatrix();
}
std::vector<Syncable*> Camera::getSyncables() {
return{ &_position, &_rotation, &_scaling };
}
} // namespace openspace

View File

@@ -26,6 +26,8 @@
#include <ghoul/misc/assert.h>
#include <fstream>
namespace openspace {
FactoryManager* FactoryManager::_manager = nullptr;
@@ -57,9 +59,94 @@ FactoryManager& FactoryManager::ref() {
return *_manager;
}
void FactoryManager::addFactory(std::unique_ptr<ghoul::TemplateFactoryBase> factory) {
void FactoryManager::addFactory(std::unique_ptr<ghoul::TemplateFactoryBase> factory,
std::string name
) {
ghoul_assert(factory, "Factory must not be nullptr");
_factories.push_back(std::move(factory));
_factories.push_back({ std::move(factory), std::move(name) });
}
void FactoryManager::writeDocumentation(const std::string& file, const std::string& type) {
if (type == "text") {
std::ofstream f;
f.exceptions(~std::ofstream::goodbit);
f.open(file);
for (const FactoryInfo& factoryInfo : _factories) {
f << factoryInfo.name << '\n';
ghoul::TemplateFactoryBase* factory = factoryInfo.factory.get();
for (const std::string& c : factory->registeredClasses()) {
f << '\t' << c << '\n';
}
f << "\n\n";
}
}
else if (type == "html") {
#ifdef JSON
std::stringstream json;
json << "[";
for (const FactoryInfo& factoryInfo : _factories) {
json << "{";
json << "\"name\": \"" << factoryInfo.name << "\",";
json << "\"classes\": [";
ghoul::TemplateFactoryBase* factory = factoryInfo.factory.get();
for (const std::string& c : factory->registeredClasses()) {
json << "\"" << c << "\",";
}
json << "]},";
}
json << "]";
// I did not check the output of this for correctness ---abock
std::string jsonText = json.str();
#else
std::ofstream f;
f.exceptions(~std::ofstream::goodbit);
f.open(file);
std::stringstream html;
html << "<html>\n"
<< "\t<head>\n"
<< "\t\t<title>Factories</title>\n"
<< "\t</head>\n"
<< "<body>\n"
<< "<table cellpadding=3 cellspacing=0 border=1>\n"
<< "\t<caption>Factories</caption>\n\n"
<< "\t<thead>\n"
<< "\t\t<tr>\n"
<< "\t\t\t<th>Type</th>\n"
<< "\t\t\t<th>Object</th>\n"
<< "\t\t</tr>\n"
<< "\t</thead>\n"
<< "\t<tbody>\n";
for (const FactoryInfo& factoryInfo : _factories) {
html << "\t\t<tr>\n"
<< "\t\t\t<td colspan=2>" << factoryInfo.name << "</td>\n";
ghoul::TemplateFactoryBase* factory = factoryInfo.factory.get();
for (const std::string& c : factory->registeredClasses()) {
html << "\t\t\t<tr><td></td><td>" << c << "</td></tr>\n";
}
html << "\t<tr><td style=\"line-height: 10px;\" colspan=2></td></tr>\n";
}
html << "\t</tbody>\n"
<< "</table>\n"
<< "</html>;";
f << html.str();
#endif
}
}
} // namespace openspace

View File

@@ -63,6 +63,10 @@ void OpenSpaceModule::deinitialize() {
internalDeinitialize();
}
std::vector<Documentation> OpenSpaceModule::documentations() const {
return {};
}
std::string OpenSpaceModule::modulePath() const {
std::string moduleName = name();
std::transform(moduleName.begin(), moduleName.end(), moduleName.begin(), tolower);

View File

@@ -44,8 +44,10 @@ SyncBuffer::~SyncBuffer() {
}
void SyncBuffer::write() {
_dataStream.resize(_encodeOffset);
_synchronizationBuffer->setVal(_dataStream);
sgct::SharedData::instance()->writeVector(_synchronizationBuffer.get());
_dataStream.resize(_n);
_encodeOffset = 0;
_decodeOffset = 0;
}

39
src/util/syncdata.cpp Normal file
View File

@@ -0,0 +1,39 @@
/*****************************************************************************************
* *
* 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 <openspace/engine/openspaceengine.h>
#include <openspace/engine/syncengine.h>
#include <openspace/util/syncdata.h>
#include <ghoul/logging/logmanager.h>
#include <string>
namespace {
const std::string _loggerCat = "SyncData";
}
namespace openspace {
}

View File

@@ -44,38 +44,13 @@ Time* Time::_instance = nullptr;
Time::Time(double secondsJ2000)
: _time(secondsJ2000)
, _dt(1.0)
//local copies
, _timeJumped(false)
, _timePaused(false)
, _jockeHasToFixThisLater(false)
//shared copies
, _sharedTime(-1.0)
, _sharedDt(1.0)
, _sharedTimeJumped(false)
//synced copies
, _syncedTime(-1.0)
, _syncedDt(1.0)
, _syncedTimeJumped(false)
{
}
{}
Time::Time(const Time& other)
: _time(other._time)
, _dt(other._dt)
//local copies
, _timeJumped(other._timeJumped)
, _timePaused(other._timePaused)
, _jockeHasToFixThisLater(other._jockeHasToFixThisLater)
//shared copies
, _sharedTime(other._sharedTime)
, _sharedDt(other._sharedDt)
, _sharedTimeJumped(other._sharedTimeJumped)
//synced copies
, _syncedTime(other._syncedTime)
, _syncedDt(other._syncedDt)
, _syncedTimeJumped(other._syncedTimeJumped)
{
}
@@ -116,19 +91,18 @@ void Time::setTime(double value, bool requireJump) {
_timeJumped = requireJump;
}
double Time::currentTime() const {
return _syncedTime;
}
double Time::unsyncedJ2000Seconds() const {
double Time::j2000Seconds() const {
return _time;
}
double Time::advanceTime(double tickTime) {
if (_timePaused)
if (_timePaused) {
return _time;
else
return _time += _dt * tickTime;
}
else {
_time += _dt * tickTime;
}
return _time;
}
void Time::setDeltaTime(double deltaT) {
@@ -136,11 +110,11 @@ void Time::setDeltaTime(double deltaT) {
}
double Time::deltaTime() const {
return _syncedDt;
return _dt;
}
void Time::setPause(bool pause) {
_timePaused = pause;
_timePaused = pause;
}
bool Time::togglePause() {
@@ -153,12 +127,12 @@ void Time::setTime(std::string time, bool requireJump) {
_timeJumped = requireJump;
}
std::string Time::currentTimeUTC() const {
return SpiceManager::ref().dateFromEphemerisTime(_syncedTime);
std::string Time::UTC() const {
return SpiceManager::ref().dateFromEphemerisTime(_time);
}
std::string Time::ISO8601() const {
std::string datetime = SpiceManager::ref().dateFromEphemerisTime(_syncedTime);
std::string datetime = SpiceManager::ref().dateFromEphemerisTime(_time);
std::string month = datetime.substr(5, 3);
std::string MM = "";
@@ -180,56 +154,8 @@ std::string Time::ISO8601() const {
return datetime;
}
void Time::serialize(SyncBuffer* syncBuffer) {
_syncMutex.lock();
syncBuffer->encode(_sharedTime);
syncBuffer->encode(_sharedDt);
syncBuffer->encode(_sharedTimeJumped);
_syncMutex.unlock();
}
void Time::deserialize(SyncBuffer* syncBuffer) {
_syncMutex.lock();
syncBuffer->decode(_sharedTime);
syncBuffer->decode(_sharedDt);
syncBuffer->decode(_sharedTimeJumped);
if (_sharedTimeJumped)
_jockeHasToFixThisLater = true;
_syncMutex.unlock();
}
void Time::postSynchronizationPreDraw() {
_syncMutex.lock();
_syncedTime = _sharedTime;
_syncedDt = _sharedDt;
_syncedTimeJumped = _sharedTimeJumped;
if (_jockeHasToFixThisLater) {
_syncedTimeJumped = true;
_jockeHasToFixThisLater = false;
}
_syncMutex.unlock();
}
void Time::preSynchronization() {
_syncMutex.lock();
_sharedTime = _time;
_sharedDt = _dt;
_sharedTimeJumped = _timeJumped;
_syncMutex.unlock();
}
bool Time::timeJumped() const {
return _syncedTimeJumped;
return _timeJumped;
}
void Time::setTimeJumped(bool jumped) {
@@ -240,6 +166,10 @@ bool Time::paused() const {
return _timePaused;
}
std::vector<Syncable*> Time::getSyncables() {
return{ &_time, &_dt, &_timeJumped};
}
scripting::LuaLibrary Time::luaLibrary() {
return {
"time",
@@ -288,7 +218,7 @@ scripting::LuaLibrary Time::luaLibrary() {
"the J2000 epoch"
},
{
"currentTimeUTC",
"UTC",
&luascriptfunctions::time_currentTimeUTC,
"",
"Returns the current time as an ISO 8601 date string "

View File

@@ -139,18 +139,18 @@ int time_setTime(lua_State* L) {
* It is returned by calling the Time::currentTime method.
*/
int time_currentTime(lua_State* L) {
lua_pushnumber(L, openspace::Time::ref().currentTime());
lua_pushnumber(L, openspace::Time::ref().j2000Seconds());
return 1;
}
/**
* \ingroup LuaScripts
* currentTimeUTC():
* UTC():
* Returns the current simulation time as a structured ISO 8601 string using the UTC
* timezone by calling the Time::currentTimeUTC method
* timezone by calling the Time::UTC method
*/
int time_currentTimeUTC(lua_State* L) {
lua_pushstring(L, openspace::Time::ref().currentTimeUTC().c_str());
lua_pushstring(L, openspace::Time::ref().UTC().c_str());
return 1;
}

View File

@@ -38,7 +38,6 @@ void TimeManager::preSynchronization(double dt) {
} else {
consumeKeyframes(dt);
}
Time::ref().preSynchronization();
}
void TimeManager::consumeKeyframes(double dt) {
@@ -85,7 +84,7 @@ void TimeManager::consumeKeyframes(double dt) {
// Do not interpolate with time jumping keyframes.
// Instead, wait until their timestamp and apply them directly.
if (next._requiresTimeJump) {
time.setTime(time.currentTime() + dt * time.deltaTime(), false);
time.setTime(time.j2000Seconds() + dt * time.deltaTime(), false);
return;
}
@@ -99,7 +98,7 @@ void TimeManager::consumeKeyframes(double dt) {
double parameter = (t1 - t0) / (t2 - t0);
double y0 = time.currentTime();
double y0 = time.j2000Seconds();
double yPrime0 = time.deltaTime();
double y2 = next._time;