diff --git a/source/base/StarAssets.cpp b/source/base/StarAssets.cpp index e5313ea..ae2d087 100644 --- a/source/base/StarAssets.cpp +++ b/source/base/StarAssets.cpp @@ -862,7 +862,10 @@ shared_ptr Assets::loadImage(AssetPath const& path) const { auto newData = make_shared(); Image newImage = *source->image; path.directives.forEach([&](auto const& entry) { - processImageOperation(entry.operation, newImage, [&](String const& ref) { return references.get(ref).get(); }); + if (auto error = entry.operation.ptr()) + std::rethrow_exception(error->exception); + else + processImageOperation(entry.operation, newImage, [&](String const& ref) { return references.get(ref).get(); }); }); newData->image = make_shared(move(newImage)); return newData; diff --git a/source/core/StarDirectives.cpp b/source/core/StarDirectives.cpp index 9214abf..1245eae 100644 --- a/source/core/StarDirectives.cpp +++ b/source/core/StarDirectives.cpp @@ -56,7 +56,7 @@ void Directives::parse(String const& directives) { ImageOperation operation = imageOperationFromString(str); newList.emplace_back(move(operation), move(str)); } catch (StarException const& e) { - Logger::logf(LogLevel::Error, "Error parsing image operation: %s", e.what()); + newList.emplace_back(ErrorImageOperation{ std::current_exception() }, move(str)); } } } @@ -214,7 +214,10 @@ inline Image DirectivesGroup::applyNewImage(Image const& image) const { void DirectivesGroup::applyExistingImage(Image& image) const { forEach([&](auto const& entry) { - processImageOperation(entry.operation, image); + if (auto error = entry.operation.ptr()) + std::rethrow_exception(error->exception); + else + processImageOperation(entry.operation, image); }); } diff --git a/source/core/StarImageProcessing.hpp b/source/core/StarImageProcessing.hpp index 30640bf..ed560af 100644 --- a/source/core/StarImageProcessing.hpp +++ b/source/core/StarImageProcessing.hpp @@ -18,6 +18,10 @@ Image scaleBicubic(Image const& srcImage, Vec2F const& scale); StringList colorDirectivesFromConfig(JsonArray const& directives); String paletteSwapDirectivesFromConfig(Json const& swaps); +struct ErrorImageOperation { + std::exception_ptr exception; +}; + struct HueShiftImageOperation { // Specify hue shift angle as -360 to 360 rather than -1 to 1 static HueShiftImageOperation hueShiftDegrees(float degrees); @@ -129,7 +133,7 @@ struct FlipImageOperation { Mode mode; }; -typedef Variant ImageOperation; diff --git a/source/game/StarImageMetadataDatabase.cpp b/source/game/StarImageMetadataDatabase.cpp index 3bf8d96..d15d802 100644 --- a/source/game/StarImageMetadataDatabase.cpp +++ b/source/game/StarImageMetadataDatabase.cpp @@ -183,6 +183,8 @@ Vec2U ImageMetadataDatabase::calculateImageSize(AssetPath const& path) const { OperationSizeAdjust(Vec2U& size) : imageSize(size), hasError(false) {}; + void operator()(ErrorImageOperation const&) {} + void operator()(HueShiftImageOperation const&) {} void operator()(SaturationShiftImageOperation const&) {} diff --git a/source/game/StarObject.cpp b/source/game/StarObject.cpp index 0441262..df3ecdf 100644 --- a/source/game/StarObject.cpp +++ b/source/game/StarObject.cpp @@ -145,7 +145,19 @@ void Object::init(World* world, EntityId entityId, EntityMode mode) { if (isMaster()) { auto colorName = configValue("color", "default").toString(); - setImageKey("color", colorName); + auto colorEnd = colorName.find('?'); + if (colorEnd != NPos) { + setImageKey("color", colorName); + m_colorDirectives = colorName.substr(colorEnd); + } + else + m_colorDirectives = ""; + + m_directives = ""; + if (auto directives = configValue("")) { + if (directives.isType(Json::Type::String)) + m_directives.parse(directives.toString()); + } if (m_config->lightColors.contains(colorName)) m_lightSourceColor.set(m_config->lightColors.get(colorName)); @@ -1205,10 +1217,15 @@ List Object::orientationDrawables(size_t orientationIndex) const { m_orientationDrawablesCache = make_pair(orientationIndex, List()); for (auto const& layer : orientation->imageLayers) { Drawable drawable = layer; - auto& image = drawable.imagePart().image; - image = AssetPath::join(image).replaceTags(m_imageKeys, true, "default"); + auto& imagePart = drawable.imagePart(); + imagePart.image.directives.clear(); + imagePart.image = AssetPath::join(imagePart.image).replaceTags(m_imageKeys, true, "default"); + imagePart.image.directives = layer.imagePart().image.directives; + imagePart.addDirectives(m_colorDirectives).addDirectives(m_directives); + if (orientation->flipImages) drawable.scale(Vec2F(-1, 1), drawable.boundBox(false).center() - drawable.position); + m_orientationDrawablesCache->second.append(move(drawable)); } } diff --git a/source/game/StarObject.hpp b/source/game/StarObject.hpp index 1a43eb6..3d5f302 100644 --- a/source/game/StarObject.hpp +++ b/source/game/StarObject.hpp @@ -218,6 +218,9 @@ private: float m_animationTimer; int m_currentFrame; + Directives m_directives; + Directives m_colorDirectives; + Maybe> m_lightFlickering; EntityTileDamageStatusPtr m_tileDamageStatus; diff --git a/source/windowing/StarButtonWidget.cpp b/source/windowing/StarButtonWidget.cpp index d70941e..0c323aa 100644 --- a/source/windowing/StarButtonWidget.cpp +++ b/source/windowing/StarButtonWidget.cpp @@ -25,6 +25,7 @@ ButtonWidget::ButtonWidget() { auto interfaceConfig = assets->json("/interface.config"); m_pressedOffset = jsonToVec2I(interfaceConfig.get("buttonPressedOffset")); m_fontSize = interfaceConfig.query("font.buttonSize").toInt(); + m_fontDirectives = interfaceConfig.queryString("font.defaultDirectives", ""); m_font = interfaceConfig.query("font.defaultFont").toString(); } @@ -89,6 +90,7 @@ void ButtonWidget::renderImpl() { if (!m_text.empty()) { auto& guiContext = GuiContext::singleton(); + guiContext.setFontProcessingDirectives(m_fontDirectives); guiContext.setFontSize(m_fontSize); guiContext.setFont(m_font); if (m_disabled) @@ -100,6 +102,7 @@ void ButtonWidget::renderImpl() { guiContext.setFontMode(FontMode::Shadow); guiContext.renderInterfaceText(m_text, {textPosition, m_hTextAnchor, VerticalAnchor::VMidAnchor}); guiContext.setFontMode(FontMode::Normal); + guiContext.setFontProcessingDirectives(""); } } @@ -302,6 +305,10 @@ void ButtonWidget::setFontSize(int size) { m_fontSize = size; } +void ButtonWidget::setFontDirectives(String directives) { + m_fontDirectives = directives; +} + void ButtonWidget::setTextOffset(Vec2I textOffset) { m_textOffset = textOffset; } diff --git a/source/windowing/StarButtonWidget.hpp b/source/windowing/StarButtonWidget.hpp index baaab00..e39c90e 100644 --- a/source/windowing/StarButtonWidget.hpp +++ b/source/windowing/StarButtonWidget.hpp @@ -69,6 +69,7 @@ public: virtual void setText(String const& text); virtual void setFontSize(int size); + virtual void setFontDirectives(String directives); virtual void setTextOffset(Vec2I textOffset); void setTextAlign(HorizontalAnchor hAnchor); @@ -122,6 +123,7 @@ protected: int m_fontSize; String m_font; + String m_fontDirectives; String m_text; Vec2I m_textOffset; diff --git a/source/windowing/StarCanvasWidget.cpp b/source/windowing/StarCanvasWidget.cpp index 873702b..2e66759 100644 --- a/source/windowing/StarCanvasWidget.cpp +++ b/source/windowing/StarCanvasWidget.cpp @@ -234,6 +234,7 @@ void CanvasWidget::renderText(Vec2F const& renderingOffset, String const& s, Tex TextPositioning translatedPosition = position; translatedPosition.pos += renderingOffset; context.renderInterfaceText(s, translatedPosition); + context.setDefaultLineSpacing(); context.setDefaultFont(); context.setFontProcessingDirectives(""); diff --git a/source/windowing/StarWidgetParsing.cpp b/source/windowing/StarWidgetParsing.cpp index db1fa1a..4ffc921 100644 --- a/source/windowing/StarWidgetParsing.cpp +++ b/source/windowing/StarWidgetParsing.cpp @@ -183,6 +183,9 @@ WidgetConstructResult WidgetParser::buttonHandler(String const& name, Json const if (config.contains("fontSize")) button->setFontSize(config.getInt("fontSize")); + if (config.contains("fontDirectives")) + button->setFontDirectives(config.getString("fontDirectives")); + if (config.contains("fontColor")) button->setFontColor(jsonToColor(config.get("fontColor")));