From 988c0b481708b123f781a271818361c234664f0f Mon Sep 17 00:00:00 2001 From: Guzul Date: Tue, 26 Sep 2023 13:34:30 +0300 Subject: [PATCH] Add opacity support to Placemarks, Paths, Ellipses, Polygons, SurfaceImages and Labels. --- .../earth/worldwind/draw/DrawShapeState.kt | 6 ++++++ .../worldwind/draw/DrawableScreenTexture.kt | 2 ++ .../kotlin/earth/worldwind/draw/DrawableShape.kt | 1 + .../worldwind/draw/DrawableSurfaceTexture.kt | 4 ++++ .../render/program/BasicShaderProgram.kt | 15 +++++++++++++-- .../render/program/SurfaceTextureProgram.kt | 16 ++++++++++++++-- .../kotlin/earth/worldwind/shape/Ellipse.kt | 2 ++ .../kotlin/earth/worldwind/shape/Label.kt | 2 ++ .../kotlin/earth/worldwind/shape/Path.kt | 2 ++ .../kotlin/earth/worldwind/shape/Placemark.kt | 2 ++ .../kotlin/earth/worldwind/shape/Polygon.kt | 3 +++ .../kotlin/earth/worldwind/shape/SurfaceImage.kt | 1 + 12 files changed, 52 insertions(+), 4 deletions(-) diff --git a/worldwind/src/commonMain/kotlin/earth/worldwind/draw/DrawShapeState.kt b/worldwind/src/commonMain/kotlin/earth/worldwind/draw/DrawShapeState.kt index 3661356ca..e23cc7f5e 100644 --- a/worldwind/src/commonMain/kotlin/earth/worldwind/draw/DrawShapeState.kt +++ b/worldwind/src/commonMain/kotlin/earth/worldwind/draw/DrawShapeState.kt @@ -23,6 +23,7 @@ open class DrawShapeState internal constructor() { var enableDepthWrite = true var depthOffset = 0.0 protected val color = Color() + protected var opacity: Float = 1.0f protected var lineWidth = 1f protected var texture: Texture? = null protected val texCoordMatrix = Matrix3() @@ -40,6 +41,7 @@ open class DrawShapeState internal constructor() { enableDepthTest = true depthOffset = 0.0 color.set(1f, 1f, 1f, 1f) + opacity = 1.0f lineWidth = 1f texture = null texCoordMatrix.setToIdentity() @@ -51,6 +53,8 @@ open class DrawShapeState internal constructor() { fun color(color: Color) = apply { this.color.copy(color) } + fun opacity(opacity: Float) = apply { this.opacity = opacity } + fun lineWidth(width: Float) = apply { lineWidth = width } fun texture(texture: Texture?) = apply { this.texture = texture } @@ -69,6 +73,7 @@ open class DrawShapeState internal constructor() { prim.type = type prim.offset = offset prim.color.copy(color) + prim.opacity = opacity prim.lineWidth = lineWidth prim.texture = texture prim.texCoordMatrix.copy(texCoordMatrix) @@ -82,6 +87,7 @@ open class DrawShapeState internal constructor() { var type = 0 var offset = 0 val color = Color() + var opacity: Float = 1.0f var lineWidth = 0f var texture: Texture? = null val texCoordMatrix = Matrix3() diff --git a/worldwind/src/commonMain/kotlin/earth/worldwind/draw/DrawableScreenTexture.kt b/worldwind/src/commonMain/kotlin/earth/worldwind/draw/DrawableScreenTexture.kt index ca18f86be..261f53988 100644 --- a/worldwind/src/commonMain/kotlin/earth/worldwind/draw/DrawableScreenTexture.kt +++ b/worldwind/src/commonMain/kotlin/earth/worldwind/draw/DrawableScreenTexture.kt @@ -14,6 +14,7 @@ import kotlin.jvm.JvmStatic open class DrawableScreenTexture protected constructor(): Drawable { val unitSquareTransform = Matrix4() val color = Color() + var opacity: Float = 1.0f var enableDepthTest = true var program: BasicShaderProgram? = null var texture: Texture? = null @@ -76,6 +77,7 @@ open class DrawableScreenTexture protected constructor(): Drawable { // Use the drawable's color. program.loadColor(drawable.color) + program.loadOpacity(opacity) // Attempt to bind the drawable's texture, configuring the shader program appropriately if there is no texture // or if the texture failed to bind. diff --git a/worldwind/src/commonMain/kotlin/earth/worldwind/draw/DrawableShape.kt b/worldwind/src/commonMain/kotlin/earth/worldwind/draw/DrawableShape.kt index dfa594c09..1e98454fc 100644 --- a/worldwind/src/commonMain/kotlin/earth/worldwind/draw/DrawableShape.kt +++ b/worldwind/src/commonMain/kotlin/earth/worldwind/draw/DrawableShape.kt @@ -72,6 +72,7 @@ open class DrawableShape protected constructor(): Drawable { for (idx in 0 until drawState.primCount) { val prim = drawState.prims[idx] program.loadColor(prim.color) + program.loadOpacity(prim.opacity) if (prim.texture?.bindTexture(dc) == true) { program.loadTexCoordMatrix(prim.texCoordMatrix) program.enableTexture(true) diff --git a/worldwind/src/commonMain/kotlin/earth/worldwind/draw/DrawableSurfaceTexture.kt b/worldwind/src/commonMain/kotlin/earth/worldwind/draw/DrawableSurfaceTexture.kt index 5cff2e45c..687d197eb 100644 --- a/worldwind/src/commonMain/kotlin/earth/worldwind/draw/DrawableSurfaceTexture.kt +++ b/worldwind/src/commonMain/kotlin/earth/worldwind/draw/DrawableSurfaceTexture.kt @@ -12,6 +12,7 @@ import kotlin.jvm.JvmStatic open class DrawableSurfaceTexture protected constructor(): Drawable { val sector = Sector() val color = Color() + var opacity: Float = 1.0f val texCoordMatrix = Matrix3() var texture: Texture? = null var program: SurfaceTextureProgram? = null @@ -30,6 +31,7 @@ open class DrawableSurfaceTexture protected constructor(): Drawable { program: SurfaceTextureProgram?, sector: Sector?, texture: Texture?, texCoordMatrix: Matrix3? ) = apply { if (sector != null) this.sector.copy(sector) else this.sector.setEmpty() + this.opacity = 1f this.color.set(1f, 1f, 1f, 1f) if (texCoordMatrix != null) this.texCoordMatrix.copy(texCoordMatrix) else this.texCoordMatrix.setToIdentity() this.texture = texture @@ -123,6 +125,8 @@ open class DrawableSurfaceTexture protected constructor(): Drawable { // Use the surface texture's RGBA color. program.loadColor(texture.color) + // Use the surface texture's opacity. + program.loadOpacity(texture.opacity) // Draw the terrain as triangles. terrain.drawTriangles(dc) diff --git a/worldwind/src/commonMain/kotlin/earth/worldwind/render/program/BasicShaderProgram.kt b/worldwind/src/commonMain/kotlin/earth/worldwind/render/program/BasicShaderProgram.kt index 25665c6a4..e0304dc91 100644 --- a/worldwind/src/commonMain/kotlin/earth/worldwind/render/program/BasicShaderProgram.kt +++ b/worldwind/src/commonMain/kotlin/earth/worldwind/render/program/BasicShaderProgram.kt @@ -34,6 +34,7 @@ open class BasicShaderProgram : AbstractShaderProgram() { uniform bool enablePickMode; uniform bool enableTexture; uniform vec4 color; + uniform float opacity; uniform sampler2D texSampler; varying vec2 texCoord; @@ -47,10 +48,10 @@ open class BasicShaderProgram : AbstractShaderProgram() { gl_FragColor = color * texMask; } else if (!enablePickMode && enableTexture) { /* Modulate the RGBA color with the 2D texture's RGBA color. */ - gl_FragColor = color * texture2D(texSampler, texCoord); + gl_FragColor = color * texture2D(texSampler, texCoord) * opacity; } else { /* Return the RGBA color as-is. */ - gl_FragColor = color; + gl_FragColor = color * opacity; } } """.trimIndent() @@ -62,12 +63,14 @@ open class BasicShaderProgram : AbstractShaderProgram() { protected val mvpMatrix = Matrix4() protected val texCoordMatrix = Matrix3() protected val color = Color() + protected var opacity = 1.0f protected var enablePickModeId = KglUniformLocation.NONE protected var enableTextureId = KglUniformLocation.NONE protected var mvpMatrixId = KglUniformLocation.NONE protected var texCoordMatrixId = KglUniformLocation.NONE protected var texSamplerId = KglUniformLocation.NONE protected var colorId = KglUniformLocation.NONE + protected var opacityId = KglUniformLocation.NONE private val array = FloatArray(16) override fun initProgram(dc: DrawContext) { @@ -85,6 +88,8 @@ open class BasicShaderProgram : AbstractShaderProgram() { colorId = gl.getUniformLocation(program, "color") val alpha = color.alpha gl.uniform4f(colorId, color.red * alpha, color.green * alpha, color.blue * alpha, alpha) + opacityId = gl.getUniformLocation(program, "opacity") + gl.uniform1f(opacityId, opacity) texSamplerId = gl.getUniformLocation(program, "texSampler") gl.uniform1i(texSamplerId, 0) // GL_TEXTURE0 } @@ -124,4 +129,10 @@ open class BasicShaderProgram : AbstractShaderProgram() { gl.uniform4f(colorId, color.red * alpha, color.green * alpha, color.blue * alpha, alpha) } } + fun loadOpacity(opacity: Float) { + if (this.opacity != opacity) { + this.opacity = opacity + gl.uniform1f(opacityId, opacity) + } + } } \ No newline at end of file diff --git a/worldwind/src/commonMain/kotlin/earth/worldwind/render/program/SurfaceTextureProgram.kt b/worldwind/src/commonMain/kotlin/earth/worldwind/render/program/SurfaceTextureProgram.kt index 679ed2cf0..2ad010c29 100644 --- a/worldwind/src/commonMain/kotlin/earth/worldwind/render/program/SurfaceTextureProgram.kt +++ b/worldwind/src/commonMain/kotlin/earth/worldwind/render/program/SurfaceTextureProgram.kt @@ -45,6 +45,7 @@ open class SurfaceTextureProgram : AbstractShaderProgram() { uniform bool enablePickMode; uniform bool enableTexture; uniform vec4 color; + uniform float opacity; uniform sampler2D texSampler; varying vec2 texCoord; @@ -65,10 +66,10 @@ open class SurfaceTextureProgram : AbstractShaderProgram() { } else if (!enablePickMode && enableTexture) { /* Using the first texture coordinate, modulate the RGBA color with the 2D texture's RGBA color. Finally, modulate by the tile mask to suppress fragments outside the surface tile. */ - gl_FragColor = color * texture2D(texSampler, texCoord) * tileMask; + gl_FragColor = color * texture2D(texSampler, texCoord) * opacity * tileMask; } else { /* Modulate the RGBA color by the tile mask to suppress fragments outside the surface tile. */ - gl_FragColor = color * tileMask; + gl_FragColor = color * opacity * tileMask; } } """.trimIndent() @@ -83,9 +84,11 @@ open class SurfaceTextureProgram : AbstractShaderProgram() { protected var texCoordMatrixId = KglUniformLocation.NONE protected var texSamplerId = KglUniformLocation.NONE protected var colorId = KglUniformLocation.NONE + protected var opacityId = KglUniformLocation.NONE private val mvpMatrixArray = FloatArray(16) private val texCoordMatrixArray = FloatArray(9 * 2) private val color = Color() + protected var opacity = 1.0f override fun initProgram(dc: DrawContext) { super.initProgram(dc) @@ -103,6 +106,8 @@ open class SurfaceTextureProgram : AbstractShaderProgram() { colorId = gl.getUniformLocation(program, "color") color.set(1f, 1f, 1f, 1f) // opaque white gl.uniform4f(colorId, color.red, color.green, color.blue, color.alpha) + opacityId = gl.getUniformLocation(program, "opacity") + gl.uniform1f(opacityId, opacity) texSamplerId = gl.getUniformLocation(program, "texSampler") gl.uniform1i(texSamplerId, 0) // GL_TEXTURE0 } @@ -129,4 +134,11 @@ open class SurfaceTextureProgram : AbstractShaderProgram() { gl.uniform4f(colorId, color.red * a, color.green * a, color.blue * a, a) } } + + fun loadOpacity(opacity: Float) { + if (this.opacity != opacity) { + this.opacity = opacity + gl.uniform1f(opacityId, opacity) + } + } } \ No newline at end of file diff --git a/worldwind/src/commonMain/kotlin/earth/worldwind/shape/Ellipse.kt b/worldwind/src/commonMain/kotlin/earth/worldwind/shape/Ellipse.kt index f70146213..b1244d415 100644 --- a/worldwind/src/commonMain/kotlin/earth/worldwind/shape/Ellipse.kt +++ b/worldwind/src/commonMain/kotlin/earth/worldwind/shape/Ellipse.kt @@ -311,6 +311,7 @@ open class Ellipse @JvmOverloads constructor( // Configure the drawable to display the shape's interior. drawState.color(if (rc.isPickMode) pickColor else activeAttributes.interiorColor) + drawState.opacity(rc.currentLayer.opacity) drawState.texCoordAttrib(2 /*size*/, 12 /*offset in bytes*/) val top = drawState.elementBuffer!!.ranges[TOP_RANGE]!! drawState.drawElements(GL_TRIANGLE_STRIP, top.length, GL_UNSIGNED_SHORT, top.lower * 2 /*offset*/) @@ -336,6 +337,7 @@ open class Ellipse @JvmOverloads constructor( // Configure the drawable to display the shape's outline. drawState.color(if (rc.isPickMode) pickColor else activeAttributes.outlineColor) + drawState.opacity(rc.currentLayer.opacity) drawState.lineWidth(activeAttributes.outlineWidth) drawState.texCoordAttrib(1 /*size*/, 20 /*offset in bytes*/) val outline = drawState.elementBuffer!!.ranges[OUTLINE_RANGE]!! diff --git a/worldwind/src/commonMain/kotlin/earth/worldwind/shape/Label.kt b/worldwind/src/commonMain/kotlin/earth/worldwind/shape/Label.kt index 36336c2fa..df8d1888b 100644 --- a/worldwind/src/commonMain/kotlin/earth/worldwind/shape/Label.kt +++ b/worldwind/src/commonMain/kotlin/earth/worldwind/shape/Label.kt @@ -186,6 +186,7 @@ open class Label @JvmOverloads constructor( // Obtain a pooled drawable and configure it to draw the label's text. val pool = rc.getDrawablePool() val drawable = DrawableScreenTexture.obtain(pool) + drawable.opacity = rc.currentLayer.opacity // Use the basic GLSL program to draw the text. drawable.program = rc.getShaderProgram { BasicShaderProgram() } @@ -200,6 +201,7 @@ open class Label @JvmOverloads constructor( // in the texture's color. if (rc.isPickMode) drawable.color.copy(renderData.pickColor) else drawable.color.set(1f, 1f, 1f, 1f) + drawable.opacity = rc.currentLayer.opacity drawable.texture = texture drawable.enableDepthTest = activeAttributes.isDepthTest diff --git a/worldwind/src/commonMain/kotlin/earth/worldwind/shape/Path.kt b/worldwind/src/commonMain/kotlin/earth/worldwind/shape/Path.kt index beb40d994..6b785532f 100644 --- a/worldwind/src/commonMain/kotlin/earth/worldwind/shape/Path.kt +++ b/worldwind/src/commonMain/kotlin/earth/worldwind/shape/Path.kt @@ -111,6 +111,8 @@ open class Path @JvmOverloads constructor( } } + drawState.opacity(rc.currentLayer.opacity) + // Configure the drawable to display the shape's outline. Increase surface shape line widths by 1/2 pixel. Lines // drawn indirectly offscreen framebuffer appear thinner when sampled as a texture. if (activeAttributes.isDrawOutline) { diff --git a/worldwind/src/commonMain/kotlin/earth/worldwind/shape/Placemark.kt b/worldwind/src/commonMain/kotlin/earth/worldwind/shape/Placemark.kt index 000542484..cf9b38f47 100644 --- a/worldwind/src/commonMain/kotlin/earth/worldwind/shape/Placemark.kt +++ b/worldwind/src/commonMain/kotlin/earth/worldwind/shape/Placemark.kt @@ -413,8 +413,10 @@ open class Placemark @JvmOverloads constructor( // the active attributes' image source and its associated tex coord transform. If the texture is not specified // or not available, draw a simple colored square. drawable.color.copy(if (rc.isPickMode) pickColor else activeAttributes.imageColor) + drawable.opacity = rc.currentLayer.opacity drawable.texture = activeTexture drawable.enableDepthTest = activeAttributes.isDepthTest + drawable.opacity = rc.currentLayer.opacity } /** diff --git a/worldwind/src/commonMain/kotlin/earth/worldwind/shape/Polygon.kt b/worldwind/src/commonMain/kotlin/earth/worldwind/shape/Polygon.kt index 7c30402e5..829712ebe 100644 --- a/worldwind/src/commonMain/kotlin/earth/worldwind/shape/Polygon.kt +++ b/worldwind/src/commonMain/kotlin/earth/worldwind/shape/Polygon.kt @@ -203,6 +203,7 @@ open class Polygon @JvmOverloads constructor( // Configure the drawable to display the shape's interior top. drawState.color(if (rc.isPickMode) pickColor else activeAttributes.interiorColor) + drawState.opacity(rc.currentLayer.opacity) drawState.texCoordAttrib(2 /*size*/, 12 /*offset in bytes*/) drawState.drawElements(GL_TRIANGLES, topElements.size, GL_UNSIGNED_SHORT, 0 /*offset*/) @@ -228,6 +229,7 @@ open class Polygon @JvmOverloads constructor( // Configure the drawable to display the shape's outline. drawState.color(if (rc.isPickMode) pickColor else activeAttributes.outlineColor) + drawState.opacity(rc.currentLayer.opacity) drawState.lineWidth(activeAttributes.outlineWidth) drawState.texCoordAttrib(1 /*size*/, 20 /*offset in bytes*/) drawState.drawElements( @@ -238,6 +240,7 @@ open class Polygon @JvmOverloads constructor( // Configure the drawable to display the shape's extruded verticals. if (activeAttributes.isDrawVerticals && isExtrude) { drawState.color(if (rc.isPickMode) pickColor else activeAttributes.outlineColor) + drawState.opacity(rc.currentLayer.opacity) drawState.lineWidth(activeAttributes.outlineWidth) drawState.texture(null) drawState.drawElements( diff --git a/worldwind/src/commonMain/kotlin/earth/worldwind/shape/SurfaceImage.kt b/worldwind/src/commonMain/kotlin/earth/worldwind/shape/SurfaceImage.kt index 0f32b307d..b2425165a 100644 --- a/worldwind/src/commonMain/kotlin/earth/worldwind/shape/SurfaceImage.kt +++ b/worldwind/src/commonMain/kotlin/earth/worldwind/shape/SurfaceImage.kt @@ -20,6 +20,7 @@ open class SurfaceImage(sector: Sector, var imageSource: ImageSource): AbstractS val program = getShaderProgram(rc) val pool = rc.getDrawablePool() val drawable = DrawableSurfaceTexture.obtain(pool).set(program, sector, texture, texture.coordTransform) + drawable.opacity = rc.currentLayer.opacity rc.offerSurfaceDrawable(drawable, 0.0 /*z-order*/) // Enqueue a picked object that associates the drawable surface texture with this surface image.