From 7263867bbc2f648fccafa89e9931844fdf7c781b Mon Sep 17 00:00:00 2001 From: Christoph Maurhofer Date: Wed, 31 Jan 2024 07:05:48 +0100 Subject: [PATCH 1/2] Add stripe support for colored polygons in vector layers --- .../graphics/objects/PolygonGroup2dOpenGl.cpp | 5 + .../graphics/objects/PolygonGroup2dOpenGl.h | 1 + .../ColorPolygonGroup2dShaderOpenGl.cpp | 130 +++++++++++++----- .../shader/ColorPolygonGroup2dShaderOpenGl.h | 7 +- .../graphics/shader/ShaderFactoryOpenGl.cpp | 4 +- .../cpp/graphics/shader/ShaderFactoryOpenGl.h | 2 +- .../graphics/shader/ShaderFactoryInterface.kt | 8 +- .../shader/NativeShaderFactoryInterface.cpp | 9 +- .../shader/NativeShaderFactoryInterface.h | 4 +- .../ios/MCShaderFactoryInterface+Private.mm | 8 +- bridging/ios/MCShaderFactoryInterface.h | 2 +- djinni/graphics/shader/shader.djinni | 2 +- shared/public/PolygonVectorLayerDescription.h | 26 +++- shared/public/ShaderFactoryInterface.h | 2 +- .../Tiled2dMapVectorLayerParserHelper.cpp | 3 +- .../Tiled2dMapVectorBackgroundSubLayer.cpp | 2 +- .../polygon/Tiled2dMapVectorPolygonTile.cpp | 12 +- .../polygon/Tiled2dMapVectorPolygonTile.h | 1 + 18 files changed, 159 insertions(+), 69 deletions(-) diff --git a/android/src/main/cpp/graphics/objects/PolygonGroup2dOpenGl.cpp b/android/src/main/cpp/graphics/objects/PolygonGroup2dOpenGl.cpp index b051f63c2..3e936101d 100644 --- a/android/src/main/cpp/graphics/objects/PolygonGroup2dOpenGl.cpp +++ b/android/src/main/cpp/graphics/objects/PolygonGroup2dOpenGl.cpp @@ -70,6 +70,7 @@ void PolygonGroup2dOpenGl::setup(const std::shared_ptr<::RenderingContextInterfa glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); mvpMatrixHandle = glGetUniformLocation(program, "uMVPMatrix"); + scaleFactorHandle = glGetUniformLocation(program, "scaleFactors"); ready = true; glDataBuffersGenerated = true; @@ -119,6 +120,10 @@ void PolygonGroup2dOpenGl::render(const std::shared_ptr<::RenderingContextInterf glUseProgram(program); glUniformMatrix4fv(mvpMatrixHandle, 1, false, (GLfloat *)mvpMatrix); + if (scaleFactorHandle >= 0) { + glUniform2f(scaleFactorHandle, screenPixelAsRealMeterFactor, + pow(2.0, ceil(log2(screenPixelAsRealMeterFactor)))); + } shaderProgram->preRender(context); diff --git a/android/src/main/cpp/graphics/objects/PolygonGroup2dOpenGl.h b/android/src/main/cpp/graphics/objects/PolygonGroup2dOpenGl.h index be59ea9ba..336a0a58a 100644 --- a/android/src/main/cpp/graphics/objects/PolygonGroup2dOpenGl.h +++ b/android/src/main/cpp/graphics/objects/PolygonGroup2dOpenGl.h @@ -57,6 +57,7 @@ class PolygonGroup2dOpenGl : public GraphicsObjectInterface, int program = 0; int mvpMatrixHandle; + int scaleFactorHandle; int positionHandle; int styleIndexHandle; GLuint attribBuffer = -1; diff --git a/android/src/main/cpp/graphics/shader/ColorPolygonGroup2dShaderOpenGl.cpp b/android/src/main/cpp/graphics/shader/ColorPolygonGroup2dShaderOpenGl.cpp index 861ee15e2..b56f068eb 100644 --- a/android/src/main/cpp/graphics/shader/ColorPolygonGroup2dShaderOpenGl.cpp +++ b/android/src/main/cpp/graphics/shader/ColorPolygonGroup2dShaderOpenGl.cpp @@ -13,12 +13,12 @@ #include "OpenGlHelper.h" #include "ColorPolygonGroup2dShaderOpenGl.h" -ColorPolygonGroup2dShaderOpenGl::ColorPolygonGroup2dShaderOpenGl() { +ColorPolygonGroup2dShaderOpenGl::ColorPolygonGroup2dShaderOpenGl(bool isStriped) + : isStriped(isStriped), + programName(std::string("UBMAP_ColorPolygonGroupShaderOpenGl_") + (isStriped ? "striped" : "std")) { this->polygonStyles.resize(sizeStyleValuesArray); } -const std::string ColorPolygonGroup2dShaderOpenGl::programName = "UBMAP_ColorPolygonGroupShaderOpenGl"; - std::shared_ptr ColorPolygonGroup2dShaderOpenGl::asShaderProgramInterface() { return shared_from_this(); } std::string ColorPolygonGroup2dShaderOpenGl::getProgramName() { return programName; } @@ -72,42 +72,98 @@ void ColorPolygonGroup2dShaderOpenGl::setStyles(const ::SharedBytes & styles) { } std::string ColorPolygonGroup2dShaderOpenGl::getVertexShader() { - return OMMVersionedGlesShaderCode(320 es, - precision highp float; - - uniform mat4 uMVPMatrix; - in vec2 vPosition; - in float vStyleIndex; - // polygonStyles: {vec4 color, float opacity} - stride = 5 - uniform float polygonStyles[5 * 16]; - uniform int numStyles; - - out vec4 color; - - void main() { - int styleIndex = int(floor(vStyleIndex + 0.5)); - if (styleIndex < 0) { - styleIndex = 0; - } else if (styleIndex > numStyles) { - styleIndex = numStyles; + return isStriped ? OMMVersionedGlesShaderCode(320 es, + // Striped Shader + precision highp float; + + uniform mat4 uMVPMatrix; + in vec2 vPosition; + in float vStyleIndex; + // polygonStyles: {vec4 color, float opacity, stripe width, gap width} - stride = 7 + uniform float polygonStyles[7 * 16]; + uniform int numStyles; + + out vec4 color; + out vec2 stripeInfo; + out vec2 uv; + + void main() { + int styleIndex = int(floor(vStyleIndex + 0.5)); + if (styleIndex < 0) { + styleIndex = 0; + } else if (styleIndex > numStyles) { + styleIndex = numStyles; + } + styleIndex = styleIndex * 5; + color = vec4(polygonStyles[styleIndex], polygonStyles[styleIndex + 1], + polygonStyles[styleIndex + 2], polygonStyles[styleIndex + 3] * polygonStyles[styleIndex + 4]); + stripeInfo = vec2(polygonStyles[styleIndex + 5], polygonStyles[styleIndex + 6]); + uv = vPosition; + gl_Position = uMVPMatrix * vec4(vPosition, 0.0, 1.0); } - styleIndex = styleIndex * 5; - color = vec4(polygonStyles[styleIndex], polygonStyles[styleIndex + 1], - polygonStyles[styleIndex + 2], polygonStyles[styleIndex + 3] * polygonStyles[styleIndex + 4]); - gl_Position = uMVPMatrix * vec4(vPosition, 0.0, 1.0); - }); + ) : OMMVersionedGlesShaderCode(320 es, + // Default Color Shader + precision highp float; + + uniform mat4 uMVPMatrix; + in vec2 vPosition; + in float vStyleIndex; + // polygonStyles: {vec4 color, float opacity} - stride = 5 + uniform float polygonStyles[5 * 16]; + uniform int numStyles; + + out vec4 color; + + void main() { + int styleIndex = int(floor(vStyleIndex + 0.5)); + if (styleIndex < 0) { + styleIndex = 0; + } else if (styleIndex > numStyles) { + styleIndex = numStyles; + } + styleIndex = styleIndex * 5; + color = vec4(polygonStyles[styleIndex], polygonStyles[styleIndex + 1], + polygonStyles[styleIndex + 2], polygonStyles[styleIndex + 3] * polygonStyles[styleIndex + 4]); + gl_Position = uMVPMatrix * vec4(vPosition, 0.0, 1.0); + }); } std::string ColorPolygonGroup2dShaderOpenGl::getFragmentShader() { - return OMMVersionedGlesShaderCode(320 es, - precision highp float; - - in vec4 color; - out vec4 fragmentColor; - - void main() { - fragmentColor = color; - fragmentColor.a = 1.0; - fragmentColor *= color.a; - }); + return isStriped ? OMMVersionedGlesShaderCode(320 es, + // Striped Shader + precision highp float; + + uniform vec2 scaleFactors; + + in vec4 color; + in vec2 stripeInfo; + in vec2 uv; + + out vec4 fragmentColor; + + void main() { + float disPx = (uv.x + uv.y) / scaleFactors.y; + float totalPx = stripeInfo.x + stripeInfo.y; + float adjLineWPx = stripeInfo.x / scaleFactors.y * scaleFactors.x; + if (mod(disPx, totalPx) > adjLineWPx) { + fragmentColor = vec4(0.0); + return; + } + + fragmentColor = color; + fragmentColor.a = 1.0; + fragmentColor *= color.a; + } + ) : OMMVersionedGlesShaderCode(320 es, + // Default Color Shader + precision highp float; + + in vec4 color; + out vec4 fragmentColor; + + void main() { + fragmentColor = color; + fragmentColor.a = 1.0; + fragmentColor *= color.a; + }); } diff --git a/android/src/main/cpp/graphics/shader/ColorPolygonGroup2dShaderOpenGl.h b/android/src/main/cpp/graphics/shader/ColorPolygonGroup2dShaderOpenGl.h index ca4efb521..2b171e873 100644 --- a/android/src/main/cpp/graphics/shader/ColorPolygonGroup2dShaderOpenGl.h +++ b/android/src/main/cpp/graphics/shader/ColorPolygonGroup2dShaderOpenGl.h @@ -19,7 +19,7 @@ class ColorPolygonGroup2dShaderOpenGl : public BaseShaderProgramOpenGl, public PolygonGroupShaderInterface, public std::enable_shared_from_this { public: - ColorPolygonGroup2dShaderOpenGl(); + ColorPolygonGroup2dShaderOpenGl(bool isStriped); virtual std::shared_ptr asShaderProgramInterface() override; @@ -37,12 +37,13 @@ class ColorPolygonGroup2dShaderOpenGl : public BaseShaderProgramOpenGl, virtual std::string getFragmentShader() override; private: - const static std::string programName; + bool isStriped = false; + const std::string programName; std::recursive_mutex styleMutex; std::vector polygonStyles; GLint numStyles = 0; - const int sizeStyleValues = 5; + const int sizeStyleValues = isStriped ? 7 : 5; const int sizeStyleValuesArray = sizeStyleValues * 16; }; diff --git a/android/src/main/cpp/graphics/shader/ShaderFactoryOpenGl.cpp b/android/src/main/cpp/graphics/shader/ShaderFactoryOpenGl.cpp index 00b033220..709b3348c 100644 --- a/android/src/main/cpp/graphics/shader/ShaderFactoryOpenGl.cpp +++ b/android/src/main/cpp/graphics/shader/ShaderFactoryOpenGl.cpp @@ -46,8 +46,8 @@ std::shared_ptr ShaderFactoryOpenGl::createColorCirc return std::make_shared(); } -std::shared_ptr ShaderFactoryOpenGl::createPolygonGroupShader() { - return std::make_shared(); +std::shared_ptr ShaderFactoryOpenGl::createPolygonGroupShader(bool isStriped) { + return std::make_shared(isStriped); } std::shared_ptr ShaderFactoryOpenGl::createPolygonPatternGroupShader(bool fadeInPattern) { diff --git a/android/src/main/cpp/graphics/shader/ShaderFactoryOpenGl.h b/android/src/main/cpp/graphics/shader/ShaderFactoryOpenGl.h index b18d7967a..833385a0f 100644 --- a/android/src/main/cpp/graphics/shader/ShaderFactoryOpenGl.h +++ b/android/src/main/cpp/graphics/shader/ShaderFactoryOpenGl.h @@ -25,7 +25,7 @@ class ShaderFactoryOpenGl : public ShaderFactoryInterface { std::shared_ptr createColorCircleShader() override; - std::shared_ptr createPolygonGroupShader() override; + std::shared_ptr createPolygonGroupShader(bool isStriped) override; std::shared_ptr createPolygonPatternGroupShader(bool fadeInPattern) override; diff --git a/bridging/android/java/io/openmobilemaps/mapscore/shared/graphics/shader/ShaderFactoryInterface.kt b/bridging/android/java/io/openmobilemaps/mapscore/shared/graphics/shader/ShaderFactoryInterface.kt index a37ab9a7a..8f79dfb7a 100644 --- a/bridging/android/java/io/openmobilemaps/mapscore/shared/graphics/shader/ShaderFactoryInterface.kt +++ b/bridging/android/java/io/openmobilemaps/mapscore/shared/graphics/shader/ShaderFactoryInterface.kt @@ -18,7 +18,7 @@ abstract class ShaderFactoryInterface { abstract fun createColorCircleShader(): ColorCircleShaderInterface - abstract fun createPolygonGroupShader(): PolygonGroupShaderInterface + abstract fun createPolygonGroupShader(isStriped: Boolean): PolygonGroupShaderInterface abstract fun createPolygonPatternGroupShader(fadeInPattern: Boolean): PolygonPatternGroupShaderInterface @@ -77,11 +77,11 @@ abstract class ShaderFactoryInterface { } private external fun native_createColorCircleShader(_nativeRef: Long): ColorCircleShaderInterface - override fun createPolygonGroupShader(): PolygonGroupShaderInterface { + override fun createPolygonGroupShader(isStriped: Boolean): PolygonGroupShaderInterface { assert(!this.destroyed.get()) { error("trying to use a destroyed object") } - return native_createPolygonGroupShader(this.nativeRef) + return native_createPolygonGroupShader(this.nativeRef, isStriped) } - private external fun native_createPolygonGroupShader(_nativeRef: Long): PolygonGroupShaderInterface + private external fun native_createPolygonGroupShader(_nativeRef: Long, isStriped: Boolean): PolygonGroupShaderInterface override fun createPolygonPatternGroupShader(fadeInPattern: Boolean): PolygonPatternGroupShaderInterface { assert(!this.destroyed.get()) { error("trying to use a destroyed object") } diff --git a/bridging/android/jni/graphics/shader/NativeShaderFactoryInterface.cpp b/bridging/android/jni/graphics/shader/NativeShaderFactoryInterface.cpp index 7c3ed424d..ab8381447 100644 --- a/bridging/android/jni/graphics/shader/NativeShaderFactoryInterface.cpp +++ b/bridging/android/jni/graphics/shader/NativeShaderFactoryInterface.cpp @@ -66,11 +66,12 @@ NativeShaderFactoryInterface::JavaProxy::~JavaProxy() = default; ::djinni::jniExceptionCheck(jniEnv); return ::djinni_generated::NativeColorCircleShaderInterface::toCpp(jniEnv, jret); } -/*not-null*/ std::shared_ptr<::PolygonGroupShaderInterface> NativeShaderFactoryInterface::JavaProxy::createPolygonGroupShader() { +/*not-null*/ std::shared_ptr<::PolygonGroupShaderInterface> NativeShaderFactoryInterface::JavaProxy::createPolygonGroupShader(bool c_isStriped) { auto jniEnv = ::djinni::jniGetThreadEnv(); ::djinni::JniLocalScope jscope(jniEnv, 10); const auto& data = ::djinni::JniClass<::djinni_generated::NativeShaderFactoryInterface>::get(); - auto jret = jniEnv->CallObjectMethod(Handle::get().get(), data.method_createPolygonGroupShader); + auto jret = jniEnv->CallObjectMethod(Handle::get().get(), data.method_createPolygonGroupShader, + ::djinni::get(::djinni::Bool::fromCpp(jniEnv, c_isStriped))); ::djinni::jniExceptionCheck(jniEnv); return ::djinni_generated::NativePolygonGroupShaderInterface::toCpp(jniEnv, jret); } @@ -176,11 +177,11 @@ CJNIEXPORT jobject JNICALL Java_io_openmobilemaps_mapscore_shared_graphics_shade } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */) } -CJNIEXPORT jobject JNICALL Java_io_openmobilemaps_mapscore_shared_graphics_shader_ShaderFactoryInterface_00024CppProxy_native_1createPolygonGroupShader(JNIEnv* jniEnv, jobject /*this*/, jlong nativeRef) +CJNIEXPORT jobject JNICALL Java_io_openmobilemaps_mapscore_shared_graphics_shader_ShaderFactoryInterface_00024CppProxy_native_1createPolygonGroupShader(JNIEnv* jniEnv, jobject /*this*/, jlong nativeRef, jboolean j_isStriped) { try { const auto& ref = ::djinni::objectFromHandleAddress<::ShaderFactoryInterface>(nativeRef); - auto r = ref->createPolygonGroupShader(); + auto r = ref->createPolygonGroupShader(::djinni::Bool::toCpp(jniEnv, j_isStriped)); return ::djinni::release(::djinni_generated::NativePolygonGroupShaderInterface::fromCpp(jniEnv, r)); } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */) } diff --git a/bridging/android/jni/graphics/shader/NativeShaderFactoryInterface.h b/bridging/android/jni/graphics/shader/NativeShaderFactoryInterface.h index 1d96bdb50..0b56c9a0f 100644 --- a/bridging/android/jni/graphics/shader/NativeShaderFactoryInterface.h +++ b/bridging/android/jni/graphics/shader/NativeShaderFactoryInterface.h @@ -38,7 +38,7 @@ class NativeShaderFactoryInterface final : ::djinni::JniInterface<::ShaderFactor /*not-null*/ std::shared_ptr<::LineGroupShaderInterface> createLineGroupShader() override; /*not-null*/ std::shared_ptr<::ColorShaderInterface> createColorShader() override; /*not-null*/ std::shared_ptr<::ColorCircleShaderInterface> createColorCircleShader() override; - /*not-null*/ std::shared_ptr<::PolygonGroupShaderInterface> createPolygonGroupShader() override; + /*not-null*/ std::shared_ptr<::PolygonGroupShaderInterface> createPolygonGroupShader(bool isStriped) override; /*not-null*/ std::shared_ptr<::PolygonPatternGroupShaderInterface> createPolygonPatternGroupShader(bool fadeInPattern) override; /*not-null*/ std::shared_ptr<::TextShaderInterface> createTextShader() override; /*not-null*/ std::shared_ptr<::TextInstancedShaderInterface> createTextInstancedShader() override; @@ -56,7 +56,7 @@ class NativeShaderFactoryInterface final : ::djinni::JniInterface<::ShaderFactor const jmethodID method_createLineGroupShader { ::djinni::jniGetMethodID(clazz.get(), "createLineGroupShader", "()Lio/openmobilemaps/mapscore/shared/graphics/shader/LineGroupShaderInterface;") }; const jmethodID method_createColorShader { ::djinni::jniGetMethodID(clazz.get(), "createColorShader", "()Lio/openmobilemaps/mapscore/shared/graphics/shader/ColorShaderInterface;") }; const jmethodID method_createColorCircleShader { ::djinni::jniGetMethodID(clazz.get(), "createColorCircleShader", "()Lio/openmobilemaps/mapscore/shared/graphics/shader/ColorCircleShaderInterface;") }; - const jmethodID method_createPolygonGroupShader { ::djinni::jniGetMethodID(clazz.get(), "createPolygonGroupShader", "()Lio/openmobilemaps/mapscore/shared/graphics/shader/PolygonGroupShaderInterface;") }; + const jmethodID method_createPolygonGroupShader { ::djinni::jniGetMethodID(clazz.get(), "createPolygonGroupShader", "(Z)Lio/openmobilemaps/mapscore/shared/graphics/shader/PolygonGroupShaderInterface;") }; const jmethodID method_createPolygonPatternGroupShader { ::djinni::jniGetMethodID(clazz.get(), "createPolygonPatternGroupShader", "(Z)Lio/openmobilemaps/mapscore/shared/graphics/shader/PolygonPatternGroupShaderInterface;") }; const jmethodID method_createTextShader { ::djinni::jniGetMethodID(clazz.get(), "createTextShader", "()Lio/openmobilemaps/mapscore/shared/graphics/shader/TextShaderInterface;") }; const jmethodID method_createTextInstancedShader { ::djinni::jniGetMethodID(clazz.get(), "createTextInstancedShader", "()Lio/openmobilemaps/mapscore/shared/graphics/shader/TextInstancedShaderInterface;") }; diff --git a/bridging/ios/MCShaderFactoryInterface+Private.mm b/bridging/ios/MCShaderFactoryInterface+Private.mm index dcd7124e5..040cffe7d 100644 --- a/bridging/ios/MCShaderFactoryInterface+Private.mm +++ b/bridging/ios/MCShaderFactoryInterface+Private.mm @@ -78,9 +78,9 @@ - (id)initWithCpp:(const std::shared_ptr<::ShaderFactoryInterface>&)cppRef } DJINNI_TRANSLATE_EXCEPTIONS() } -- (nullable id)createPolygonGroupShader { +- (nullable id)createPolygonGroupShader:(BOOL)isStriped { try { - auto objcpp_result_ = _cppRefHandle.get()->createPolygonGroupShader(); + auto objcpp_result_ = _cppRefHandle.get()->createPolygonGroupShader(::djinni::Bool::toCpp(isStriped)); return ::djinni_generated::PolygonGroupShaderInterface::fromCpp(objcpp_result_); } DJINNI_TRANSLATE_EXCEPTIONS() } @@ -171,10 +171,10 @@ - (id)initWithCpp:(const std::shared_ptr<::ShaderFactoryInterface>&)cppRef return ::djinni_generated::ColorCircleShaderInterface::toCpp(objcpp_result_); } } - /*not-null*/ std::shared_ptr<::PolygonGroupShaderInterface> createPolygonGroupShader() override + /*not-null*/ std::shared_ptr<::PolygonGroupShaderInterface> createPolygonGroupShader(bool c_isStriped) override { @autoreleasepool { - auto objcpp_result_ = [djinni_private_get_proxied_objc_object() createPolygonGroupShader]; + auto objcpp_result_ = [djinni_private_get_proxied_objc_object() createPolygonGroupShader:(::djinni::Bool::fromCpp(c_isStriped))]; return ::djinni_generated::PolygonGroupShaderInterface::toCpp(objcpp_result_); } } diff --git a/bridging/ios/MCShaderFactoryInterface.h b/bridging/ios/MCShaderFactoryInterface.h index f8eeb05f6..57e40b8e7 100644 --- a/bridging/ios/MCShaderFactoryInterface.h +++ b/bridging/ios/MCShaderFactoryInterface.h @@ -28,7 +28,7 @@ - (nullable id)createColorCircleShader; -- (nullable id)createPolygonGroupShader; +- (nullable id)createPolygonGroupShader:(BOOL)isStriped; - (nullable id)createPolygonPatternGroupShader:(BOOL)fadeInPattern; diff --git a/djinni/graphics/shader/shader.djinni b/djinni/graphics/shader/shader.djinni index c7c74dc49..86798bcc8 100644 --- a/djinni/graphics/shader/shader.djinni +++ b/djinni/graphics/shader/shader.djinni @@ -24,7 +24,7 @@ shader_factory_interface = interface +c +j +o { create_line_group_shader(): line_group_shader_interface; create_color_shader() : color_shader_interface; create_color_circle_shader() : color_circle_shader_interface; - create_polygon_group_shader(): polygon_group_shader_interface; + create_polygon_group_shader(is_striped: bool): polygon_group_shader_interface; create_polygon_pattern_group_shader(fade_in_pattern: bool): polygon_pattern_group_shader_interface; create_text_shader() : text_shader_interface; diff --git a/shared/public/PolygonVectorLayerDescription.h b/shared/public/PolygonVectorLayerDescription.h index faf27c70b..3a521a874 100644 --- a/shared/public/PolygonVectorLayerDescription.h +++ b/shared/public/PolygonVectorLayerDescription.h @@ -21,25 +21,28 @@ class PolygonVectorStyle { std::shared_ptr fillOpacity, std::shared_ptr fillPattern, std::shared_ptr blendMode, - bool fadeInPattern): + bool fadeInPattern, + std::shared_ptr stripeWidth): fillColor(fillColor), fillOpacity(fillOpacity), fillPattern(fillPattern), blendMode(blendMode), - fadeInPattern(fadeInPattern) {} + fadeInPattern(fadeInPattern), + stripeWidth(stripeWidth) {} PolygonVectorStyle(PolygonVectorStyle &style) : fillColor(style.fillColor), fillOpacity(style.fillOpacity), fillPattern(style.fillPattern), blendMode(style.blendMode), - fadeInPattern(style.fadeInPattern) {} + fadeInPattern(style.fadeInPattern), + stripeWidth(style.stripeWidth) {} UsedKeysCollection getUsedKeys() const { UsedKeysCollection usedKeys; std::shared_ptr values[] = { - fillColor, fillOpacity, fillPattern + fillColor, fillOpacity, fillPattern, stripeWidth }; for (auto const &value: values) { @@ -75,18 +78,33 @@ class PolygonVectorStyle { return fillPattern ? true : false; } + std::vector getStripeWidth(const EvaluationContext &context) { + static const std::vector defaultValue = {1.0, 1.0}; + auto stripeInfo = stripeWidthEvaluator.getResult(stripeWidth, context, defaultValue); + for (int i = 0; i < stripeInfo.size(); ++i) { + stripeInfo[i] = stripeInfo[i] * context.dpFactor; + } + return stripeInfo; + } + + bool isStripedPotentially() { + return stripeWidth ? true : false; + } + public: std::shared_ptr fillColor; std::shared_ptr fillOpacity; std::shared_ptr fillPattern; std::shared_ptr blendMode; bool fadeInPattern; + std::shared_ptr stripeWidth; private: ValueEvaluator fillColorEvaluator; ValueEvaluator fillOpacityEvaluator; ValueEvaluator fillPatternEvaluator; ValueEvaluator blendModeEvaluator; + ValueEvaluator> stripeWidthEvaluator; }; class PolygonVectorLayerDescription: public VectorLayerDescription { diff --git a/shared/public/ShaderFactoryInterface.h b/shared/public/ShaderFactoryInterface.h index 81b90daee..5de77679d 100644 --- a/shared/public/ShaderFactoryInterface.h +++ b/shared/public/ShaderFactoryInterface.h @@ -32,7 +32,7 @@ class ShaderFactoryInterface { virtual /*not-null*/ std::shared_ptr createColorCircleShader() = 0; - virtual /*not-null*/ std::shared_ptr createPolygonGroupShader() = 0; + virtual /*not-null*/ std::shared_ptr createPolygonGroupShader(bool isStriped) = 0; virtual /*not-null*/ std::shared_ptr createPolygonPatternGroupShader(bool fadeInPattern) = 0; diff --git a/shared/src/map/layers/tiled/vector/Tiled2dMapVectorLayerParserHelper.cpp b/shared/src/map/layers/tiled/vector/Tiled2dMapVectorLayerParserHelper.cpp index f688f4e70..e4b024d82 100644 --- a/shared/src/map/layers/tiled/vector/Tiled2dMapVectorLayerParserHelper.cpp +++ b/shared/src/map/layers/tiled/vector/Tiled2dMapVectorLayerParserHelper.cpp @@ -381,7 +381,8 @@ Tiled2dMapVectorLayerParserResult Tiled2dMapVectorLayerParserHelper::parseStyleJ parser.parseValue(val["paint"]["fill-opacity"]), parser.parseValue(val["paint"]["fill-pattern"]), blendMode, - (!val["layout"]["fadeInPattern"].is_null()) && val["layout"].value("fadeInPattern", false)); + (!val["layout"]["fadeInPattern"].is_null()) && val["layout"].value("fadeInPattern", false), + parser.parseValue(val["paint"]["stripe-width"])); auto layerDesc = std::make_shared(val["id"], val["source"], diff --git a/shared/src/map/layers/tiled/vector/sublayers/background/Tiled2dMapVectorBackgroundSubLayer.cpp b/shared/src/map/layers/tiled/vector/sublayers/background/Tiled2dMapVectorBackgroundSubLayer.cpp index 5f4725c69..2f055a8d8 100644 --- a/shared/src/map/layers/tiled/vector/sublayers/background/Tiled2dMapVectorBackgroundSubLayer.cpp +++ b/shared/src/map/layers/tiled/vector/sublayers/background/Tiled2dMapVectorBackgroundSubLayer.cpp @@ -58,7 +58,7 @@ void Tiled2dMapVectorBackgroundSubLayer::onAdded(const std::shared_ptrgetShaderFactory()->createPolygonGroupShader(); + auto shader = mapInterface->getShaderFactory()->createPolygonGroupShader(false); auto object = mapInterface->getGraphicsObjectFactory()->createPolygonGroup(shader->asShaderProgramInterface()); object->asGraphicsObject()->setDebugLabel(description->identifier); polygonObject = std::make_shared(mapInterface->getCoordinateConverterHelper(), object, shader); diff --git a/shared/src/map/layers/tiled/vector/tiles/polygon/Tiled2dMapVectorPolygonTile.cpp b/shared/src/map/layers/tiled/vector/tiles/polygon/Tiled2dMapVectorPolygonTile.cpp index 6455578b4..9da3501f9 100644 --- a/shared/src/map/layers/tiled/vector/tiles/polygon/Tiled2dMapVectorPolygonTile.cpp +++ b/shared/src/map/layers/tiled/vector/tiles/polygon/Tiled2dMapVectorPolygonTile.cpp @@ -25,7 +25,8 @@ Tiled2dMapVectorPolygonTile::Tiled2dMapVectorPolygonTile(const std::weak_ptr &description, const std::shared_ptr &layerConfig, const std::shared_ptr &featureStateManager) - : Tiled2dMapVectorTile(mapInterface, tileInfo, description, layerConfig, tileCallbackInterface, featureStateManager), usedKeys(std::move(description->getUsedKeys())) { + : Tiled2dMapVectorTile(mapInterface, tileInfo, description, layerConfig, tileCallbackInterface, featureStateManager), + usedKeys(std::move(description->getUsedKeys())), isStriped(description->style.isStripedPotentially()) { isStyleZoomDependant = usedKeys.containsUsedKey(Tiled2dMapVectorStyleParser::zoomExpression); isStyleStateDependant = usedKeys.isStateDependant(); } @@ -106,8 +107,13 @@ void Tiled2dMapVectorPolygonTile::update() { shaderStyles.push_back(color.b); shaderStyles.push_back(color.a); shaderStyles.push_back(opacity * alpha); + if (isStriped) { + const auto stripeWidth = inZoomRange ? polygonDescription->style.getStripeWidth(ec) : std::vector{0.0, 0.0}; + shaderStyles.push_back(stripeWidth[0]); + shaderStyles.push_back(stripeWidth[1]); + } } - auto s = SharedBytes((int64_t)shaderStyles.data(), (int32_t)featureGroups.at(styleGroupId).size(), 5 * (int32_t)sizeof(float)); + auto s = SharedBytes((int64_t)shaderStyles.data(), (int32_t)featureGroups.at(styleGroupId).size(), (isStriped ? 7 : 5) * (int32_t)sizeof(float)); shaders[styleGroupId]->setStyles(s); } } @@ -180,7 +186,7 @@ void Tiled2dMapVectorPolygonTile::setVectorTileData(const Tiled2dMapVectorTileDa } else { styleGroupIndex = (int) featureGroups.size(); styleIndex = 0; - auto shader = shaderFactory->createPolygonGroupShader(); + auto shader = shaderFactory->createPolygonGroupShader(isStriped); auto polygonDescription = std::static_pointer_cast(description); shader->asShaderProgramInterface()->setBlendMode(polygonDescription->style.getBlendMode(EvaluationContext(0.0, dpFactor, std::make_shared(), featureStateManager))); shaders.push_back(shader); diff --git a/shared/src/map/layers/tiled/vector/tiles/polygon/Tiled2dMapVectorPolygonTile.h b/shared/src/map/layers/tiled/vector/tiles/polygon/Tiled2dMapVectorPolygonTile.h index f92164c80..156bedf56 100644 --- a/shared/src/map/layers/tiled/vector/tiles/polygon/Tiled2dMapVectorPolygonTile.h +++ b/shared/src/map/layers/tiled/vector/tiles/polygon/Tiled2dMapVectorPolygonTile.h @@ -68,6 +68,7 @@ class Tiled2dMapVectorPolygonTile UsedKeysCollection usedKeys; bool isStyleZoomDependant = true; bool isStyleStateDependant = true; + bool isStriped = false; std::optional lastZoom = std::nullopt; std::optional lastInZoomRange = std::nullopt; From 1844d06dd916325a4cc70548203420a615afd5f0 Mon Sep 17 00:00:00 2001 From: Marco Zimmermann Date: Mon, 5 Feb 2024 15:09:02 +0100 Subject: [PATCH 2/2] adds striped polygons for iOS --- .../Model/Polygon/PolygonGroup2d.swift | 31 ++++++++++++++- ios/graphics/Pipelines/PipelineLibrary.swift | 6 ++- .../Shader/Metal/PolygonGroupShader.metal | 39 +++++++++++++++++++ ios/graphics/Shader/PolygonGroupShader.swift | 10 +++-- ios/graphics/Shader/ShaderFactory.swift | 5 ++- 5 files changed, 83 insertions(+), 8 deletions(-) diff --git a/ios/graphics/Model/Polygon/PolygonGroup2d.swift b/ios/graphics/Model/Polygon/PolygonGroup2d.swift index 77de10b37..ee125fdb0 100644 --- a/ios/graphics/Model/Polygon/PolygonGroup2d.swift +++ b/ios/graphics/Model/Polygon/PolygonGroup2d.swift @@ -21,7 +21,7 @@ final class PolygonGroup2d: BaseGraphicsObject { private var stencilState: MTLDepthStencilState? private var renderPassStencilState: MTLDepthStencilState? - + private var posOffset = SIMD2([0.0, 0.0]) init(shader: MCShaderProgramInterface, metalContext: MetalContext) { guard let shader = shader as? PolygonGroupShader else { @@ -38,7 +38,7 @@ final class PolygonGroup2d: BaseGraphicsObject { renderPass pass: MCRenderPassConfig, mvpMatrix: Int64, isMasked: Bool, - screenPixelAsRealMeterFactor _: Double) { + screenPixelAsRealMeterFactor: Double) { lock.lock() defer { lock.unlock() @@ -79,6 +79,14 @@ final class PolygonGroup2d: BaseGraphicsObject { encoder.setVertexBytes(matrixPointer, length: 64, index: 1) } + if self.shader.isStriped { + encoder.setVertexBytes(&posOffset, length: MemoryLayout>.stride, index: 2) + + let p : Float = Float(screenPixelAsRealMeterFactor) + var scaleFactors = SIMD2([p, pow(2.0, ceil(log2(p)))]) + encoder.setFragmentBytes(&scaleFactors, length: MemoryLayout>.stride, index: 2) + } + encoder.drawIndexedPrimitives(type: .triangle, indexCount: indicesCount, indexType: .uint16, @@ -107,6 +115,25 @@ extension PolygonGroup2d: MCPolygonGroup2dInterface { self.indicesCount = Int(indices.elementCount) self.verticesBuffer = verticesBuffer self.indicesBuffer = indicesBuffer + + if shader.isStriped { + if let p = UnsafeRawPointer(bitPattern: Int(vertices.address)) { + var minX = Float.greatestFiniteMagnitude + var minY = Float.greatestFiniteMagnitude + + for i in 0.. adjLineWPx) { + return float4(0.0, 1.0, 0.0, 0.0); + } + + return float4(s.color[0], s.color[1], s.color[2], 1.0) * s.opacity * s.color[3]; +} vertex PolygonPatternGroupVertexOut polygonPatternGroupVertexShader(const PolygonGroupVertexIn vertexIn [[stage_in]], diff --git a/ios/graphics/Shader/PolygonGroupShader.swift b/ios/graphics/Shader/PolygonGroupShader.swift index 81c08d47a..7d9c4eb03 100644 --- a/ios/graphics/Shader/PolygonGroupShader.swift +++ b/ios/graphics/Shader/PolygonGroupShader.swift @@ -16,12 +16,17 @@ import UIKit class PolygonGroupShader: BaseShader { var polygonStyleBuffer: MTLBuffer? - override init() { + let isStriped : Bool + + init(isStriped: Bool) { + self.isStriped = isStriped + super.init() } override func setupProgram(_: MCRenderingContextInterface?) { if pipeline == nil { - pipeline = MetalContext.current.pipelineLibrary.value(Pipeline(type: .polygonGroupShader, blendMode: blendMode).json) + let t : PipelineType = isStriped ? .polygonStripedGroupShader : .polygonGroupShader + pipeline = MetalContext.current.pipelineLibrary.value(Pipeline(type: t, blendMode: blendMode).json) } } @@ -30,7 +35,6 @@ class PolygonGroupShader: BaseShader { let pipeline else { return } context.setRenderPipelineStateIfNeeded(pipeline) - encoder.setFragmentBuffer(polygonStyleBuffer, offset: 0, index: 1) } } diff --git a/ios/graphics/Shader/ShaderFactory.swift b/ios/graphics/Shader/ShaderFactory.swift index f957b2043..5813e61e3 100644 --- a/ios/graphics/Shader/ShaderFactory.swift +++ b/ios/graphics/Shader/ShaderFactory.swift @@ -12,12 +12,13 @@ import Foundation import MapCoreSharedModule class ShaderFactory: MCShaderFactoryInterface { + func createTextShader() -> MCTextShaderInterface? { TextShader() } - func createPolygonGroupShader() -> MCPolygonGroupShaderInterface? { - PolygonGroupShader() + func createPolygonGroupShader(_ isStriped: Bool) -> MCPolygonGroupShaderInterface? { + PolygonGroupShader(isStriped: isStriped) } func createPolygonPatternGroupShader(_ fadeInPattern: Bool) -> MCPolygonPatternGroupShaderInterface? {