From 40b784f55143ab8f31f887eac0c3ae58dad90cc3 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Fri, 19 Aug 2022 11:22:10 +0300 Subject: [PATCH] More universal treatment of highlighting in three --- .../space/kscience/visionforge/StyleSheet.kt | 2 +- .../kscience/visionforge/VisionProperties.kt | 5 +- .../space/kscience/visionforge/solid/Solid.kt | 2 + .../visionforge/solid/three/ThreeCanvas.kt | 34 +++++++++--- .../solid/three/ThreeLabelFactory.kt | 8 +-- .../visionforge/solid/three/ThreeMaterials.kt | 52 +++++++++++++------ .../solid/three/ThreeMeshFactory.kt | 2 +- .../main/kotlin/three/meshline/meshLineExt.kt | 5 +- 8 files changed, 79 insertions(+), 31 deletions(-) diff --git a/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/StyleSheet.kt b/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/StyleSheet.kt index 9db79e19..7320839d 100644 --- a/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/StyleSheet.kt +++ b/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/StyleSheet.kt @@ -67,7 +67,7 @@ internal fun Vision.styleChanged(key: String, oldStyle: Meta?, newStyle: Meta?) * List of names of styles applied to this object. Order matters. Not inherited. */ public var Vision.styles: List - get() = properties.getValue(Vision.STYLE_KEY, inherit = false, includeStyles = false)?.stringList ?: emptyList() + get() = properties.own?.getValue(Vision.STYLE_KEY)?.stringList ?: emptyList() set(value) { properties.setValue(Vision.STYLE_KEY, value.map { it.asValue() }.asValue()) } diff --git a/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/VisionProperties.kt b/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/VisionProperties.kt index fd7befdf..3a80dcf2 100644 --- a/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/VisionProperties.kt +++ b/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/VisionProperties.kt @@ -143,8 +143,11 @@ private class VisionPropertiesItem( override fun hashCode(): Int = Meta.hashCode(this) } +/** + * A base implementation of [MutableVisionProperties] + */ public abstract class AbstractVisionProperties( - private val vision: Vision, + public val vision: Vision, ) : MutableVisionProperties { override val descriptor: MetaDescriptor? get() = vision.descriptor diff --git a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Solid.kt b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Solid.kt index 7d0d0b94..5585a970 100644 --- a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Solid.kt +++ b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/Solid.kt @@ -58,6 +58,8 @@ public interface Solid : Vision { public val ROTATION_KEY: Name = "rotation".asName() + public val QUATERNION_KEY: Name = "quaternion".asName() + public val X_ROTATION_KEY: Name = ROTATION_KEY + X_KEY public val Y_ROTATION_KEY: Name = ROTATION_KEY + Y_KEY public val Z_ROTATION_KEY: Name = ROTATION_KEY + Z_KEY diff --git a/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeCanvas.kt b/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeCanvas.kt index 04b04699..4e6935a8 100644 --- a/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeCanvas.kt +++ b/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeCanvas.kt @@ -20,9 +20,12 @@ import three.external.controls.OrbitControls import three.external.controls.TrackballControls import three.geometries.EdgesGeometry import three.helpers.AxesHelper +import three.materials.Material import three.math.* import three.meshline.MeshLine import three.meshline.MeshLineMaterial +import three.meshline.isMeshLineMaterial +import three.objects.LineSegments import three.objects.Mesh import three.scenes.Scene import kotlin.math.cos @@ -276,7 +279,7 @@ public class ThreeCanvas( private fun Object3D.toggleHighlight( highlight: Boolean, edgesName: String, - material: MeshLineMaterial, + material: Material, ) { if (userData[DO_NOT_HIGHLIGHT_TAG] == true) { @@ -284,16 +287,21 @@ public class ThreeCanvas( } if (isMesh(this)) { - val highlightMesh = getObjectByName(edgesName) ?: Mesh( - MeshLine(EdgesGeometry(geometry)), - material - ).also { + val highlightMesh = getObjectByName(edgesName) ?: if (isMeshLineMaterial(material)) { + Mesh( + MeshLine(EdgesGeometry(geometry)), + material + ) + } else { + LineSegments(EdgesGeometry(geometry), material) + }.also { it.name = edgesName add(it) } highlightMesh.visible = highlight } else { - children.filter { !it.name.startsWith("@") && it.name != edgesName }.forEach { + //ignore service objects if they are not statics + children.filter { it.name.startsWith("@static") || !it.name.startsWith("@") }.forEach { it.toggleHighlight(highlight, edgesName, material) } } @@ -319,15 +327,25 @@ public class ThreeCanvas( public companion object { public val SELECTED_MATERIAL: MeshLineMaterial = MeshLineMaterial().apply { color.set(Colors.ivory) - linewidth = 2.0 + thickness = 2f cached = true } public val HIGHLIGHT_MATERIAL: MeshLineMaterial = MeshLineMaterial().apply { color.set(Colors.blue) - linewidth = 2.0 + thickness = 2f cached = true } +// +// public val SELECTED_MATERIAL: LineBasicMaterial = LineBasicMaterial().apply { +// color.set(Colors.ivory) +// cached = true +// } +// +// public val HIGHLIGHT_MATERIAL: LineBasicMaterial = LineBasicMaterial().apply { +// color.set(Colors.blue) +// cached = true +// } public const val DO_NOT_HIGHLIGHT_TAG: String = "doNotHighlight" diff --git a/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeLabelFactory.kt b/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeLabelFactory.kt index 49796fb0..2bd8c572 100644 --- a/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeLabelFactory.kt +++ b/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeLabelFactory.kt @@ -1,14 +1,14 @@ package space.kscience.visionforge.solid.three -import three.core.Object3D -import three.geometries.TextBufferGeometry -import three.objects.Mesh import kotlinx.js.jso import space.kscience.dataforge.context.logger import space.kscience.dataforge.context.warn import space.kscience.visionforge.onPropertyChange import space.kscience.visionforge.solid.SolidLabel +import three.core.Object3D +import three.geometries.TextBufferGeometry +import three.objects.Mesh import kotlin.reflect.KClass /** @@ -25,7 +25,7 @@ public object ThreeLabelFactory : ThreeFactory { curveSegments = 1 }) return Mesh(textGeo, ThreeMaterials.DEFAULT).apply { - createMaterial(vision) + setMaterial(vision) updatePosition(vision) if(observe) { vision.onPropertyChange(three.context) { diff --git a/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeMaterials.kt b/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeMaterials.kt index abcd5df5..5966ee30 100644 --- a/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeMaterials.kt +++ b/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeMaterials.kt @@ -60,6 +60,7 @@ public object ThreeMaterials { color = meta[SolidMaterial.COLOR_KEY]?.threeColor() ?: DEFAULT_COLOR wireframe = meta[SolidMaterial.WIREFRAME_KEY].boolean ?: false } + else -> MeshStandardMaterial().apply { color = meta[SolidMaterial.COLOR_KEY]?.threeColor() ?: DEFAULT_COLOR emissive = meta[SolidMaterial.EMISSIVE_COLOR_KEY]?.threeColor() ?: DEFAULT_EMISSIVE_COLOR @@ -71,10 +72,18 @@ public object ThreeMaterials { needsUpdate = true } - private val materialCache = HashMap() +// private val materialCache = HashMap() +// +// internal fun cacheMaterial(meta: Meta): Material = materialCache.getOrPut(meta.hashCode()) { +// buildMaterial(meta).apply { +// cached = true +// } +// } - internal fun cacheMaterial(meta: Meta): Material = materialCache.getOrPut(meta.hashCode()) { - buildMaterial(meta).apply { + private val visionMaterialCache = HashMap() + + internal fun cacheMaterial(vision: Vision): Material = visionMaterialCache.getOrPut(vision) { + buildMaterial(vision.properties.getProperty(SolidMaterial.MATERIAL_KEY)).apply { cached = true } } @@ -84,7 +93,7 @@ public object ThreeMaterials { * Compute color */ public fun Meta.threeColor(): Color? { - if(isEmpty()) return null + if (isEmpty()) return null val value = value return if (isLeaf) { when { @@ -118,13 +127,19 @@ internal var Material.cached: Boolean userData["cached"] = value } -public fun Mesh.createMaterial(vision: Vision) { - val ownMaterialMeta = vision.properties.own?.get(SolidMaterial.MATERIAL_KEY) - if (ownMaterialMeta == null) { - if (vision is SolidReference && vision.getStyleNodes(SolidMaterial.MATERIAL_KEY).isEmpty()) { - createMaterial(vision.prototype) +public fun Mesh.setMaterial(vision: Vision) { + if ( + vision.properties.own?.get(SolidMaterial.MATERIAL_KEY) == null + && vision.getStyleNodes(SolidMaterial.MATERIAL_KEY).isEmpty() + ) { + //if this is a reference, use material of the prototype + if (vision is SolidReference) { + ThreeMaterials.cacheMaterial(vision.prototype) } else { - material = ThreeMaterials.cacheMaterial(vision.properties.getProperty(SolidMaterial.MATERIAL_KEY)) + material = vision.parent?.let { parent -> + //TODO cache parent material + ThreeMaterials.buildMaterial(parent.properties.getProperty(SolidMaterial.MATERIAL_KEY)) + } ?: ThreeMaterials.cacheMaterial(vision) } } else { material = ThreeMaterials.buildMaterial(vision.properties.getProperty(SolidMaterial.MATERIAL_KEY)) @@ -138,22 +153,27 @@ public fun Mesh.updateMaterialProperty(vision: Vision, propertyName: Name) { || propertyName == SolidMaterial.MATERIAL_KEY + SolidMaterial.TYPE_KEY ) { //generate a new material since cached material should not be changed - createMaterial(vision) + setMaterial(vision) } else { when (propertyName) { SolidMaterial.MATERIAL_COLOR_KEY -> { - material.asDynamic().color = vision.properties.getProperty(SolidMaterial.MATERIAL_COLOR_KEY).threeColor() - ?: ThreeMaterials.DEFAULT_COLOR + material.asDynamic().color = + vision.properties.getProperty(SolidMaterial.MATERIAL_COLOR_KEY).threeColor() + ?: ThreeMaterials.DEFAULT_COLOR } + SolidMaterial.SPECULAR_COLOR_KEY -> { - material.asDynamic().specular = vision.properties.getProperty(SolidMaterial.SPECULAR_COLOR_KEY).threeColor() - ?: ThreeMaterials.DEFAULT_COLOR + material.asDynamic().specular = + vision.properties.getProperty(SolidMaterial.SPECULAR_COLOR_KEY).threeColor() + ?: ThreeMaterials.DEFAULT_COLOR } + SolidMaterial.MATERIAL_EMISSIVE_COLOR_KEY -> { material.asDynamic().emissive = vision.properties.getProperty(SolidMaterial.MATERIAL_EMISSIVE_COLOR_KEY) .threeColor() ?: ThreeMaterials.BLACK_COLOR } + SolidMaterial.MATERIAL_OPACITY_KEY -> { val opacity = vision.properties.getValue( SolidMaterial.MATERIAL_OPACITY_KEY, @@ -162,12 +182,14 @@ public fun Mesh.updateMaterialProperty(vision: Vision, propertyName: Name) { material.opacity = opacity material.transparent = opacity < 1.0 } + SolidMaterial.MATERIAL_WIREFRAME_KEY -> { material.asDynamic().wireframe = vision.properties.getValue( SolidMaterial.MATERIAL_WIREFRAME_KEY, inherit = true, )?.boolean ?: false } + else -> console.warn("Unrecognized material property: $propertyName") } material.needsUpdate = true diff --git a/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeMeshFactory.kt b/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeMeshFactory.kt index ef7f5120..b27bdcab 100644 --- a/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeMeshFactory.kt +++ b/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeMeshFactory.kt @@ -85,7 +85,7 @@ public fun Solid.edges(enabled: Boolean = true, block: SolidMaterial.() -> Unit } internal fun Mesh.applyProperties(vision: Solid): Mesh = apply { - createMaterial(vision) + setMaterial(vision) applyEdges(vision) //applyWireFrame(obj) layers.set(vision.layer) diff --git a/visionforge-threejs/src/main/kotlin/three/meshline/meshLineExt.kt b/visionforge-threejs/src/main/kotlin/three/meshline/meshLineExt.kt index a2bfa57a..60047884 100644 --- a/visionforge-threejs/src/main/kotlin/three/meshline/meshLineExt.kt +++ b/visionforge-threejs/src/main/kotlin/three/meshline/meshLineExt.kt @@ -1,8 +1,11 @@ package three.meshline import three.core.BufferGeometry +import three.materials.Material import three.math.Vector3 public fun MeshLine(geometry: BufferGeometry): MeshLine = MeshLine().apply { setGeometry(geometry) } -public fun MeshLine(points: Array): MeshLine = MeshLine().apply { setPoints(points) } \ No newline at end of file +public fun MeshLine(points: Array): MeshLine = MeshLine().apply { setPoints(points) } + +internal fun isMeshLineMaterial(material: Material): Boolean = material.asDynamic().isMeshLineMaterial == true \ No newline at end of file