/***************************************************************************************** * * * OpenSpace * * * * Copyright (c) 2014-2017 * * * * Permission is hereby granted, free of charge, to any person obtaining a copy of this * * software and associated documentation files (the "Software"), to deal in the Software * * without restriction, including without limitation the rights to use, copy, modify, * * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * * permit persons to whom the Software is furnished to do so, subject to the following * * conditions: * * * * The above copyright notice and this permission notice shall be included in all copies * * or substantial portions of the Software. * * * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * ****************************************************************************************/ #include #include namespace openspace::globebrowsing { namespace { const char* _loggerCat = "Layer"; const char* keyName = "Name"; const char* keyEnabled = "Enabled"; const char* keyLayerGroupID = "LayerGroupID"; const char* keySettings = "Settings"; const char* keyAdjustment = "Adjustment"; const char* KeyBlendMode = "BlendMode"; static const openspace::properties::Property::PropertyInfo TypeInfo = { "Type", "Type", "The type of this Layer. This value is a read-only property and thus cannot be " "changed." }; static const openspace::properties::Property::PropertyInfo BlendModeInfo = { "BlendMode", "Blend Mode", "This value specifies the blend mode that is applied to this layer. The blend " "mode determines how this layer is added to the underlying layers beneath." }; static const openspace::properties::Property::PropertyInfo EnabledInfo = { "Enabled", "Enabled", "If this value is enabled, the layer will be used for the final composition of " "the planet. If this value is disabled, the layer will be ignored in the " "composition." }; static const openspace::properties::Property::PropertyInfo ResetInfo = { "Reset", "Reset", "If this value is triggered, this layer will be reset. This will delete the " "local cache for this layer and will trigger a fresh load of all tiles." }; static const openspace::properties::Property::PropertyInfo ColorInfo = { "Color", "Color", "If the 'Type' of this layer is a solid color, this value determines what this " "solid color is." }; } // namespace Layer::Layer(layergroupid::GroupID id, const ghoul::Dictionary& layerDict) : properties::PropertyOwner(layerDict.value(keyName)) , _typeOption(TypeInfo, properties::OptionProperty::DisplayType::Dropdown) , _blendModeOption(BlendModeInfo, properties::OptionProperty::DisplayType::Dropdown) , _enabled(EnabledInfo, false) , _reset(ResetInfo) , _tileProvider(nullptr) , _otherTypesProperties({ { ColorInfo, glm::vec4(1.f), glm::vec4(0.f), glm::vec4(1.f) } }) , _layerGroupId(id) { layergroupid::TypeID typeID = parseTypeIdFromDictionary(layerDict); if (typeID == layergroupid::TypeID::Unknown) { throw ghoul::RuntimeError("Unknown layer type!"); } initializeBasedOnType(typeID, layerDict); bool enabled = false; // defaults to false if unspecified layerDict.getValue(keyEnabled, enabled); _enabled.setValue(enabled); // Initialize settings ghoul::Dictionary settingsDict; if (layerDict.getValue(keySettings, settingsDict)) { _renderSettings.setValuesFromDictionary(settingsDict); } // Initiallize layer adjustment ghoul::Dictionary adjustmentDict; if (layerDict.getValue(keyAdjustment, adjustmentDict)) { _layerAdjustment.setValuesFromDictionary(adjustmentDict); } // Add options to option properties for (int i = 0; i < layergroupid::NUM_LAYER_TYPES; ++i) { _typeOption.addOption(i, layergroupid::LAYER_TYPE_NAMES[i]); } _typeOption.setValue(static_cast(typeID)); _type = static_cast(_typeOption.value()); for (int i = 0; i < layergroupid::NUM_BLEND_MODES; ++i) { _blendModeOption.addOption(i, layergroupid::BLEND_MODE_NAMES[i]); } // Initialize blend mode std::string blendModeName; if (layerDict.getValue(KeyBlendMode, blendModeName)) { layergroupid::BlendModeID blendModeID = layergroupid::getBlendModeIDFromName(blendModeName); _blendModeOption.setValue(static_cast(blendModeID)); } else { _blendModeOption.setValue(static_cast(layergroupid::BlendModeID::Normal)); } // On change callbacks definitions _enabled.onChange([&](){ if (_onChangeCallback) { _onChangeCallback(); } }); _reset.onChange([&](){ if (_tileProvider) { _tileProvider->reset(); } }); _typeOption.onChange([&](){ removeVisibleProperties(); _type = static_cast(_typeOption.value()); ghoul::Dictionary dict; initializeBasedOnType(type(), dict); addVisibleProperties(); if (_onChangeCallback) { _onChangeCallback(); } }); _blendModeOption.onChange([&](){ if (_onChangeCallback) { _onChangeCallback(); } }); _layerAdjustment.onChange([&](){ if (_onChangeCallback) { _onChangeCallback(); } }); _typeOption.setReadOnly(true); // Add the properties addProperty(_typeOption); addProperty(_blendModeOption); addProperty(_enabled); addProperty(_reset); _otherTypesProperties.color.setViewOption(properties::Property::ViewOptions::Color); addVisibleProperties(); addPropertySubOwner(_renderSettings); addPropertySubOwner(_layerAdjustment); } ChunkTilePile Layer::getChunkTilePile(const TileIndex& tileIndex, int pileSize) const { if (_tileProvider) { return _tileProvider->getChunkTilePile(tileIndex, pileSize); } else { ChunkTilePile chunkTilePile; chunkTilePile.resize(pileSize); for (int i = 0; i < pileSize; ++i) { chunkTilePile[i].tile = Tile::TileUnavailable; chunkTilePile[i].uvTransform.uvOffset = { 0, 0 }; chunkTilePile[i].uvTransform.uvScale = { 1, 1 }; } return chunkTilePile; } } Tile::Status Layer::getTileStatus(const TileIndex& index) const { if (_tileProvider) { return _tileProvider->getTileStatus(index); } else { return Tile::Status::Unavailable; } } layergroupid::TypeID Layer::type() const { return _type; }; layergroupid::BlendModeID Layer::blendMode() const { return static_cast(_blendModeOption.value()); }; TileDepthTransform Layer::depthTransform() const { if (_tileProvider) { return _tileProvider->depthTransform(); } else { return {1.0f, 0.0f}; } } bool Layer::enabled() const { return _enabled.value(); } tileprovider::TileProvider* Layer::tileProvider() const { return _tileProvider.get(); } const Layer::OtherTypesProperties& Layer::otherTypesProperties() const { return _otherTypesProperties; } const LayerRenderSettings& Layer::renderSettings() const { return _renderSettings; } const LayerAdjustment& Layer::layerAdjustment() const { return _layerAdjustment; } void Layer::onChange(std::function callback) { _onChangeCallback = callback; } void Layer::update() { if (_tileProvider) { _tileProvider->update(); } } layergroupid::TypeID Layer::parseTypeIdFromDictionary( const ghoul::Dictionary& initDict) const { if (initDict.hasKeyAndValue("Type")) { const std::string typeString = initDict.value("Type"); return layergroupid::getTypeIDFromTypeString(typeString); } else { return layergroupid::TypeID::DefaultTileLayer; } } void Layer::initializeBasedOnType(layergroupid::TypeID typeId, ghoul::Dictionary initDict) { switch (typeId) { // Intentional fall through. Same for all tile layers case layergroupid::TypeID::DefaultTileLayer: case layergroupid::TypeID::SingleImageTileLayer: case layergroupid::TypeID::SizeReferenceTileLayer: case layergroupid::TypeID::TemporalTileLayer: case layergroupid::TypeID::TileIndexTileLayer: case layergroupid::TypeID::ByIndexTileLayer: case layergroupid::TypeID::ByLevelTileLayer: { // We add the id to the dictionary since it needs to be known by // the tile provider ghoul::Dictionary tileProviderInitDict = initDict; tileProviderInitDict.setValue(keyLayerGroupID, _layerGroupId); if (tileProviderInitDict.hasKeyAndValue(keyName)) { std::string name; tileProviderInitDict.getValue(keyName, name); LDEBUG("Initializing tile provider for layer: '" + name + "'"); } _tileProvider = std::shared_ptr( tileprovider::TileProvider::createFromDictionary(typeId, tileProviderInitDict) ); break; } case layergroupid::TypeID::SolidColor: break; default: throw ghoul::RuntimeError("Unable to create layer. Unknown type."); break; } } void Layer::addVisibleProperties() { switch (type()) { // Intentional fall through. Same for all tile layers case layergroupid::TypeID::DefaultTileLayer: case layergroupid::TypeID::SingleImageTileLayer: case layergroupid::TypeID::SizeReferenceTileLayer: case layergroupid::TypeID::TemporalTileLayer: case layergroupid::TypeID::TileIndexTileLayer: case layergroupid::TypeID::ByIndexTileLayer: case layergroupid::TypeID::ByLevelTileLayer: if (_tileProvider) { addPropertySubOwner(*_tileProvider); } break; case layergroupid::TypeID::SolidColor: addProperty(_otherTypesProperties.color); default: break; } } void Layer::removeVisibleProperties() { switch (type()) { // Intentional fall through. Same for all tile layers case layergroupid::TypeID::DefaultTileLayer: case layergroupid::TypeID::SingleImageTileLayer: case layergroupid::TypeID::SizeReferenceTileLayer: case layergroupid::TypeID::TemporalTileLayer: case layergroupid::TypeID::TileIndexTileLayer: case layergroupid::TypeID::ByIndexTileLayer: case layergroupid::TypeID::ByLevelTileLayer: if (_tileProvider) { removePropertySubOwner(*_tileProvider); } break; case layergroupid::TypeID::SolidColor: removeProperty(_otherTypesProperties.color); break; default: break; } } } // namespace openspace::globebrowsing