From 66ea23ad60ec8366660930d4ede13b1b009e65be Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Mon, 21 Dec 2020 21:45:29 +0300 Subject: [PATCH] Optimized materials allocation --- .../vision/solid/demo/VariableBox.kt | 14 +-- .../kotlin/hep/dataforge/vision/Vision.kt | 28 ++--- .../kotlin/hep/dataforge/vision/VisionBase.kt | 8 +- .../kotlin/hep/dataforge/vision/misc.kt | 16 ++- .../hep/dataforge/vision/solid/SolidGroup.kt | 4 +- .../dataforge/vision/solid/SolidReference.kt | 17 ++- .../vision/solid/three/MeshThreeFactory.kt | 69 ++++++------ .../vision/solid/three/ThreeFactory.kt | 5 +- .../vision/solid/three/ThreeLabelFactory.kt | 8 +- .../vision/solid/three/ThreeMaterials.kt | 101 ++++++++++++++++-- .../info/laht/threekt/materials/Material.kt | 2 +- 11 files changed, 181 insertions(+), 91 deletions(-) diff --git a/demo/spatial-showcase/src/jsMain/kotlin/hep/dataforge/vision/solid/demo/VariableBox.kt b/demo/spatial-showcase/src/jsMain/kotlin/hep/dataforge/vision/solid/demo/VariableBox.kt index 2910e0d3..4fbb0903 100644 --- a/demo/spatial-showcase/src/jsMain/kotlin/hep/dataforge/vision/solid/demo/VariableBox.kt +++ b/demo/spatial-showcase/src/jsMain/kotlin/hep/dataforge/vision/solid/demo/VariableBox.kt @@ -11,7 +11,6 @@ import hep.dataforge.vision.solid.* import hep.dataforge.vision.solid.Solid.Companion.GEOMETRY_KEY import hep.dataforge.vision.solid.SolidMaterial.Companion.MATERIAL_COLOR_KEY import hep.dataforge.vision.solid.three.* -import hep.dataforge.vision.solid.three.ThreeMaterials.getMaterial import info.laht.threekt.core.BufferGeometry import info.laht.threekt.core.Object3D import info.laht.threekt.geometries.BoxBufferGeometry @@ -31,8 +30,8 @@ internal class VariableBox(xSize: Number, ySize: Number, zSize: Number) : ThreeV scaleX = xSize scaleY = ySize scaleZ = zSize - getProperty(MeshThreeFactory.EDGES_ENABLED_KEY, false) - getProperty(MeshThreeFactory.WIREFRAME_ENABLED_KEY, false) +// getProperty(MeshThreeFactory.EDGES_ENABLED_KEY, inherit = false, includeStyles = false) +// getProperty(MeshThreeFactory.WIREFRAME_ENABLED_KEY, inherit = false, includeStyles = false) } override fun render(three: ThreePlugin): Object3D { @@ -44,9 +43,10 @@ internal class VariableBox(xSize: Number, ySize: Number, zSize: Number) : ThreeV //JS sometimes tries to pass Geometry as BufferGeometry @Suppress("USELESS_IS_CHECK") if (geometry !is BufferGeometry) error("BufferGeometry expected") - val mesh = Mesh(geometry, getMaterial(this@VariableBox, true)).apply { + val mesh = Mesh(geometry, ThreeMaterials.DEFAULT).apply { + updateMaterial(this@VariableBox) applyEdges(this@VariableBox) - applyWireFrame(this@VariableBox) + //applyWireFrame(this@VariableBox) //set position for mesh updatePosition(this@VariableBox) @@ -69,10 +69,10 @@ internal class VariableBox(xSize: Number, ySize: Number, zSize: Number) : ThreeV mesh.scale.set(newXSize, newYSize, newZSize) mesh.updateMatrix() } - name.startsWith(MeshThreeFactory.WIREFRAME_KEY) -> mesh.applyWireFrame(this@VariableBox) + //name.startsWith(MeshThreeFactory.WIREFRAME_KEY) -> mesh.applyWireFrame(this@VariableBox) name.startsWith(MeshThreeFactory.EDGES_KEY) -> mesh.applyEdges(this@VariableBox) name.startsWith(MATERIAL_COLOR_KEY) -> { - mesh.material = getMaterial(this, true) + mesh.updateMaterial(this) } else -> mesh.updateProperty(this@VariableBox, name) } diff --git a/visionforge-core/src/commonMain/kotlin/hep/dataforge/vision/Vision.kt b/visionforge-core/src/commonMain/kotlin/hep/dataforge/vision/Vision.kt index eda9e70b..28f6b988 100644 --- a/visionforge-core/src/commonMain/kotlin/hep/dataforge/vision/Vision.kt +++ b/visionforge-core/src/commonMain/kotlin/hep/dataforge/vision/Vision.kt @@ -4,6 +4,7 @@ import hep.dataforge.meta.MetaItem import hep.dataforge.meta.MutableItemProvider import hep.dataforge.meta.descriptors.Described import hep.dataforge.meta.descriptors.NodeDescriptor +import hep.dataforge.meta.descriptors.get import hep.dataforge.names.Name import hep.dataforge.names.asName import hep.dataforge.names.toName @@ -45,8 +46,8 @@ public interface Vision : Described { */ public fun getProperty( name: Name, - inherit: Boolean? = null, - includeStyles: Boolean? = null, + inherit: Boolean = false, + includeStyles: Boolean = true, includeDefaults: Boolean = true, ): MetaItem<*>? @@ -63,14 +64,15 @@ public interface Vision : Described { * if it should include inherited properties etc. */ @OptIn(ExperimentalCoroutinesApi::class) - public val propertyChanges: Flow get() = callbackFlow { - coroutineScope { - onPropertyChange(this) { - send(it) + public val propertyChanges: Flow + get() = callbackFlow { + coroutineScope { + onPropertyChange(this) { + send(it) + } + awaitClose { cancel() } } - awaitClose { cancel() } } - } /** @@ -93,7 +95,7 @@ public interface Vision : Described { } } -public fun Vision.asyncNotifyPropertyChange(propertyName: Name){ +public fun Vision.asyncNotifyPropertyChange(propertyName: Name) { scope.launch { notifyPropertyChanged(propertyName) } @@ -120,8 +122,8 @@ public fun Vision.allProperties( ): MutableItemProvider = object : MutableItemProvider { override fun getItem(name: Name): MetaItem<*>? = getProperty( name, - inherit = inherit, - includeStyles = includeStyles, + inherit = inherit ?: (descriptor?.get(name)?.inherited != false), + includeStyles = includeStyles ?: (descriptor?.get(name)?.usesStyles == true), includeDefaults = includeDefaults ) @@ -133,8 +135,8 @@ public fun Vision.allProperties( */ public fun Vision.getProperty( key: String, - inherit: Boolean? = null, - includeStyles: Boolean? = null, + inherit: Boolean = false, + includeStyles: Boolean = true, includeDefaults: Boolean = true, ): MetaItem<*>? = getProperty(key.toName(), inherit, includeStyles, includeDefaults) diff --git a/visionforge-core/src/commonMain/kotlin/hep/dataforge/vision/VisionBase.kt b/visionforge-core/src/commonMain/kotlin/hep/dataforge/vision/VisionBase.kt index 141366d1..fdd7feed 100644 --- a/visionforge-core/src/commonMain/kotlin/hep/dataforge/vision/VisionBase.kt +++ b/visionforge-core/src/commonMain/kotlin/hep/dataforge/vision/VisionBase.kt @@ -65,15 +65,15 @@ public open class VisionBase : Vision { override fun getProperty( name: Name, - inherit: Boolean?, - includeStyles: Boolean?, + inherit: Boolean, + includeStyles: Boolean, includeDefaults: Boolean, ): MetaItem<*>? = sequence { yield(getOwnProperty(name)) - if (includeStyles ?: descriptor?.get(name)?.usesStyles != false) { + if (includeStyles) { yieldAll(getStyleItems(name)) } - if (inherit ?: descriptor?.get(name)?.inherited == true) { + if (inherit) { yield(parent?.getProperty(name, inherit, includeStyles, includeDefaults)) } yield(descriptor?.get(name)?.defaultItem()) diff --git a/visionforge-core/src/commonMain/kotlin/hep/dataforge/vision/misc.kt b/visionforge-core/src/commonMain/kotlin/hep/dataforge/vision/misc.kt index ef1882fe..047cd2fa 100644 --- a/visionforge-core/src/commonMain/kotlin/hep/dataforge/vision/misc.kt +++ b/visionforge-core/src/commonMain/kotlin/hep/dataforge/vision/misc.kt @@ -6,15 +6,13 @@ import hep.dataforge.values.asValue @DslMarker public annotation class VisionBuilder -public fun Sequence?>.merge(): MetaItem<*>? { - return when (val first = firstOrNull { it != null }) { - null -> null - is MetaItem.ValueItem -> first //fast search for first entry if it is value - is MetaItem.NodeItem -> { - //merge nodes if first encountered node is meta - val laminate: Laminate = Laminate(mapNotNull { it.node }.toList()) - MetaItem.NodeItem(laminate) - } +public fun Sequence?>.merge(): MetaItem<*>? = when (val first = firstOrNull { it != null }) { + null -> null + is MetaItem.ValueItem -> first //fast search for first entry if it is value + is MetaItem.NodeItem -> { + //merge nodes if first encountered node is meta + val laminate: Laminate = Laminate(mapNotNull { it.node }.toList()) + MetaItem.NodeItem(laminate) } } diff --git a/visionforge-solid/src/commonMain/kotlin/hep/dataforge/vision/solid/SolidGroup.kt b/visionforge-solid/src/commonMain/kotlin/hep/dataforge/vision/solid/SolidGroup.kt index e2abc4e8..4ddfe548 100644 --- a/visionforge-solid/src/commonMain/kotlin/hep/dataforge/vision/solid/SolidGroup.kt +++ b/visionforge-solid/src/commonMain/kotlin/hep/dataforge/vision/solid/SolidGroup.kt @@ -109,8 +109,8 @@ internal class Prototypes( override fun getProperty( name: Name, - inherit: Boolean?, - includeStyles: Boolean?, + inherit: Boolean, + includeStyles: Boolean, includeDefaults: Boolean, ): MetaItem<*>? = null diff --git a/visionforge-solid/src/commonMain/kotlin/hep/dataforge/vision/solid/SolidReference.kt b/visionforge-solid/src/commonMain/kotlin/hep/dataforge/vision/solid/SolidReference.kt index 63cd0672..d9fbdba0 100644 --- a/visionforge-solid/src/commonMain/kotlin/hep/dataforge/vision/solid/SolidReference.kt +++ b/visionforge-solid/src/commonMain/kotlin/hep/dataforge/vision/solid/SolidReference.kt @@ -2,7 +2,6 @@ package hep.dataforge.vision.solid import hep.dataforge.meta.* import hep.dataforge.meta.descriptors.NodeDescriptor -import hep.dataforge.meta.descriptors.get import hep.dataforge.names.* import hep.dataforge.vision.* import kotlinx.coroutines.CoroutineScope @@ -15,17 +14,17 @@ public interface SolidReference : Vision { private fun SolidReference.getRefProperty( name: Name, - inherit: Boolean?, - includeStyles: Boolean?, + inherit: Boolean, + includeStyles: Boolean, includeDefaults: Boolean, ): MetaItem<*>? { return sequence { yield(getOwnProperty(name)) - if (includeStyles ?: descriptor?.get(name)?.usesStyles != false) { + if (includeStyles) { yieldAll(getStyleItems(name)) } yield(prototype.getProperty(name, inherit, includeStyles, includeDefaults)) - if (inherit ?: descriptor?.get(name)?.inherited == true) { + if (inherit) { yield(parent?.getProperty(name, inherit)) } }.merge() @@ -77,8 +76,8 @@ public class SolidReferenceGroup( override fun getProperty( name: Name, - inherit: Boolean?, - includeStyles: Boolean?, + inherit: Boolean, + includeStyles: Boolean, includeDefaults: Boolean, ): MetaItem<*>? = getRefProperty(name, inherit, includeStyles, includeDefaults) @@ -108,8 +107,8 @@ public class SolidReferenceGroup( override fun getProperty( name: Name, - inherit: Boolean?, - includeStyles: Boolean?, + inherit: Boolean, + includeStyles: Boolean, includeDefaults: Boolean, ): MetaItem<*>? = getRefProperty(name, inherit, includeStyles, includeDefaults) diff --git a/visionforge-threejs/src/main/kotlin/hep/dataforge/vision/solid/three/MeshThreeFactory.kt b/visionforge-threejs/src/main/kotlin/hep/dataforge/vision/solid/three/MeshThreeFactory.kt index 813086fd..f04e7a1a 100644 --- a/visionforge-threejs/src/main/kotlin/hep/dataforge/vision/solid/three/MeshThreeFactory.kt +++ b/visionforge-threejs/src/main/kotlin/hep/dataforge/vision/solid/three/MeshThreeFactory.kt @@ -9,10 +9,8 @@ import hep.dataforge.names.startsWith import hep.dataforge.vision.solid.Solid import hep.dataforge.vision.solid.SolidMaterial import hep.dataforge.vision.solid.layer -import hep.dataforge.vision.solid.three.ThreeMaterials.getMaterial import info.laht.threekt.core.BufferGeometry import info.laht.threekt.geometries.EdgesGeometry -import info.laht.threekt.geometries.WireframeGeometry import info.laht.threekt.objects.LineSegments import info.laht.threekt.objects.Mesh import kotlin.reflect.KClass @@ -36,7 +34,7 @@ public abstract class MeshThreeFactory( //val meshMeta: Meta = obj.properties[Material3D.MATERIAL_KEY]?.node ?: Meta.empty - val mesh = Mesh(geometry, null).apply { + val mesh = Mesh(geometry, ThreeMaterials.DEFAULT).apply { matrixAutoUpdate = false //set position for mesh updatePosition(obj) @@ -49,11 +47,11 @@ public abstract class MeshThreeFactory( val oldGeometry = mesh.geometry as BufferGeometry val newGeometry = buildGeometry(obj) oldGeometry.attributes = newGeometry.attributes - mesh.applyWireFrame(obj) + //mesh.applyWireFrame(obj) mesh.applyEdges(obj) newGeometry.dispose() } - name.startsWith(WIREFRAME_KEY) -> mesh.applyWireFrame(obj) + //name.startsWith(WIREFRAME_KEY) -> mesh.applyWireFrame(obj) name.startsWith(EDGES_KEY) -> mesh.applyEdges(obj) else -> mesh.updateProperty(obj, name) } @@ -64,19 +62,19 @@ public abstract class MeshThreeFactory( public companion object { public val EDGES_KEY: Name = "edges".asName() - public val WIREFRAME_KEY: Name = "wireframe".asName() + //public val WIREFRAME_KEY: Name = "wireframe".asName() public val ENABLED_KEY: Name = "enabled".asName() public val EDGES_ENABLED_KEY: Name = EDGES_KEY + ENABLED_KEY public val EDGES_MATERIAL_KEY: Name = EDGES_KEY + SolidMaterial.MATERIAL_KEY - public val WIREFRAME_ENABLED_KEY: Name = WIREFRAME_KEY + ENABLED_KEY - public val WIREFRAME_MATERIAL_KEY: Name = WIREFRAME_KEY + SolidMaterial.MATERIAL_KEY + //public val WIREFRAME_ENABLED_KEY: Name = WIREFRAME_KEY + ENABLED_KEY + //public val WIREFRAME_MATERIAL_KEY: Name = WIREFRAME_KEY + SolidMaterial.MATERIAL_KEY } } internal fun Mesh.applyProperties(obj: Solid): Mesh = apply { - material = getMaterial(obj, true) + updateMaterial(obj) applyEdges(obj) - applyWireFrame(obj) + //applyWireFrame(obj) layers.enable(obj.layer) children.forEach { it.layers.enable(obj.layer) @@ -86,9 +84,16 @@ internal fun Mesh.applyProperties(obj: Solid): Mesh = apply { public fun Mesh.applyEdges(obj: Solid) { val edges = children.find { it.name == "@edges" } as? LineSegments //inherited edges definition, enabled by default - if (obj.getProperty(MeshThreeFactory.EDGES_ENABLED_KEY).boolean != false) { + if (obj.getProperty(MeshThreeFactory.EDGES_ENABLED_KEY, inherit = true, includeStyles = true).boolean != false) { val bufferGeometry = geometry as? BufferGeometry ?: return - val material = ThreeMaterials.getLineMaterial(obj.getProperty(MeshThreeFactory.EDGES_MATERIAL_KEY).node, true) + val material = ThreeMaterials.getLineMaterial( + obj.getProperty( + MeshThreeFactory.EDGES_MATERIAL_KEY, + inherit = true, + includeStyles = true + ).node, + true + ) if (edges == null) { add( LineSegments( @@ -109,23 +114,23 @@ public fun Mesh.applyEdges(obj: Solid) { } } -public fun Mesh.applyWireFrame(obj: Solid) { - children.find { it.name == "@wireframe" }?.let { - remove(it) - (it as LineSegments).dispose() - } - //inherited wireframe definition, disabled by default - if (obj.getProperty(MeshThreeFactory.WIREFRAME_ENABLED_KEY).boolean == true) { - val bufferGeometry = geometry as? BufferGeometry ?: return - val material = - ThreeMaterials.getLineMaterial(obj.getProperty(MeshThreeFactory.WIREFRAME_MATERIAL_KEY).node, true) - add( - LineSegments( - WireframeGeometry(bufferGeometry), - material - ).apply { - name = "@wireframe" - } - ) - } -} \ No newline at end of file +//public fun Mesh.applyWireFrame(obj: Solid) { +// children.find { it.name == "@wireframe" }?.let { +// remove(it) +// (it as LineSegments).dispose() +// } +// //inherited wireframe definition, disabled by default +// if (obj.getProperty(MeshThreeFactory.WIREFRAME_ENABLED_KEY).boolean == true) { +// val bufferGeometry = geometry as? BufferGeometry ?: return +// val material = +// ThreeMaterials.getLineMaterial(obj.getProperty(MeshThreeFactory.WIREFRAME_MATERIAL_KEY).node, true) +// add( +// LineSegments( +// WireframeGeometry(bufferGeometry), +// material +// ).apply { +// name = "@wireframe" +// } +// ) +// } +//} \ No newline at end of file diff --git a/visionforge-threejs/src/main/kotlin/hep/dataforge/vision/solid/three/ThreeFactory.kt b/visionforge-threejs/src/main/kotlin/hep/dataforge/vision/solid/three/ThreeFactory.kt index d6be69e1..30fa1422 100644 --- a/visionforge-threejs/src/main/kotlin/hep/dataforge/vision/solid/three/ThreeFactory.kt +++ b/visionforge-threejs/src/main/kotlin/hep/dataforge/vision/solid/three/ThreeFactory.kt @@ -7,7 +7,6 @@ import hep.dataforge.vision.Vision import hep.dataforge.vision.solid.* import hep.dataforge.vision.solid.SolidMaterial.Companion.MATERIAL_KEY import hep.dataforge.vision.solid.three.ThreeFactory.Companion.TYPE -import hep.dataforge.vision.solid.three.ThreeMaterials.getMaterial import hep.dataforge.vision.visible import info.laht.threekt.core.BufferGeometry import info.laht.threekt.core.Object3D @@ -34,7 +33,7 @@ public interface ThreeFactory { */ public fun Object3D.updatePosition(obj: Vision) { visible = obj.visible ?: true - if(obj is Solid) { + if (obj is Solid) { position.set(obj.x, obj.y, obj.z) setRotationFromEuler(obj.euler) scale.set(obj.scaleX, obj.scaleY, obj.scaleZ) @@ -47,7 +46,7 @@ public fun Object3D.updatePosition(obj: Vision) { */ public fun Object3D.updateProperty(source: Vision, propertyName: Name) { if (this is Mesh && propertyName.startsWith(MATERIAL_KEY)) { - this.material = getMaterial(source, true) + updateMaterialProperty(source, propertyName) } else if ( propertyName.startsWith(Solid.POSITION_KEY) || propertyName.startsWith(Solid.ROTATION) diff --git a/visionforge-threejs/src/main/kotlin/hep/dataforge/vision/solid/three/ThreeLabelFactory.kt b/visionforge-threejs/src/main/kotlin/hep/dataforge/vision/solid/three/ThreeLabelFactory.kt index 258628bb..8809ea2d 100644 --- a/visionforge-threejs/src/main/kotlin/hep/dataforge/vision/solid/three/ThreeLabelFactory.kt +++ b/visionforge-threejs/src/main/kotlin/hep/dataforge/vision/solid/three/ThreeLabelFactory.kt @@ -3,7 +3,6 @@ package hep.dataforge.vision.solid.three import hep.dataforge.context.logger import hep.dataforge.vision.solid.SolidLabel -import hep.dataforge.vision.solid.three.ThreeMaterials.getMaterial import info.laht.threekt.core.Object3D import info.laht.threekt.geometries.TextBufferGeometry import info.laht.threekt.objects.Mesh @@ -23,11 +22,12 @@ public object ThreeLabelFactory : ThreeFactory { height = 1 curveSegments = 1 }) - return Mesh(textGeo, getMaterial(obj, true)).apply { + return Mesh(textGeo, ThreeMaterials.DEFAULT).apply { + updateMaterial(obj) updatePosition(obj) - obj.onPropertyChange(three.updateScope){ _ -> + obj.onPropertyChange(three.updateScope) { _ -> //TODO - three.logger.warn{"Label parameter change not implemented"} + three.logger.warn { "Label parameter change not implemented" } } } } diff --git a/visionforge-threejs/src/main/kotlin/hep/dataforge/vision/solid/three/ThreeMaterials.kt b/visionforge-threejs/src/main/kotlin/hep/dataforge/vision/solid/three/ThreeMaterials.kt index 1736ce82..e9471af8 100644 --- a/visionforge-threejs/src/main/kotlin/hep/dataforge/vision/solid/three/ThreeMaterials.kt +++ b/visionforge-threejs/src/main/kotlin/hep/dataforge/vision/solid/three/ThreeMaterials.kt @@ -1,23 +1,28 @@ package hep.dataforge.vision.solid.three import hep.dataforge.meta.* +import hep.dataforge.names.Name import hep.dataforge.values.ValueType import hep.dataforge.values.int import hep.dataforge.values.string import hep.dataforge.vision.Colors import hep.dataforge.vision.Vision +import hep.dataforge.vision.allStyles +import hep.dataforge.vision.merge import hep.dataforge.vision.solid.SolidMaterial import info.laht.threekt.materials.LineBasicMaterial import info.laht.threekt.materials.Material import info.laht.threekt.materials.MeshBasicMaterial import info.laht.threekt.materials.MeshPhongMaterial import info.laht.threekt.math.Color +import info.laht.threekt.objects.Mesh public object ThreeMaterials { public val DEFAULT_COLOR: Color = Color(Colors.darkgreen) public val DEFAULT: MeshBasicMaterial = MeshBasicMaterial().apply { color.set(DEFAULT_COLOR) + cached = true } public val DEFAULT_LINE_COLOR: Color = Color(Colors.black) public val DEFAULT_LINE: LineBasicMaterial = LineBasicMaterial().apply { @@ -54,7 +59,7 @@ public object ThreeMaterials { private val materialCache = HashMap() - private fun buildMaterial(meta: Meta): Material { + internal fun buildMaterial(meta: Meta): Material { return if (meta[SolidMaterial.SPECULAR_COLOR_KEY] != null) { MeshPhongMaterial().apply { color = meta[SolidMaterial.COLOR_KEY]?.getColor() ?: DEFAULT_COLOR @@ -79,15 +84,26 @@ public object ThreeMaterials { } } - public fun getMaterial(vision3D: Vision, cache: Boolean): Material { - val meta = vision3D.getProperty(SolidMaterial.MATERIAL_KEY, inherit = true).node ?: return DEFAULT - return if (cache) { - materialCache.getOrPut(meta) { buildMaterial(meta) } - } else { - buildMaterial(meta) + internal fun cacheMeta(meta: Meta): Material = materialCache.getOrPut(meta) { + buildMaterial(meta).apply { + cached = true } } + +// internal fun getMaterial(vision: Vision, cache: Boolean): Material { +// val meta = vision.getProperty(SolidMaterial.MATERIAL_KEY, inherit = true).node ?: return DEFAULT +// return if (cache) { +// materialCache.getOrPut(meta) { +// buildMaterial(meta).apply { +// cached = true +// } +// } +// } else { +// buildMaterial(meta) +// } +// } + } /** @@ -111,3 +127,74 @@ public fun MetaItem<*>.getColor(): Color { } } +private var Material.cached: Boolean + get() = userData["cached"] == true + set(value) { + userData["cached"] = value + } + +public fun Mesh.updateMaterial(vision: Vision) { + //val meta = vision.getProperty(SolidMaterial.MATERIAL_KEY, inherit = true).node + val ownMaterialMeta = vision.getOwnProperty(SolidMaterial.MATERIAL_KEY) + val stylesMaterialMeta = vision.allStyles[SolidMaterial.MATERIAL_KEY] + val parentMaterialMeta = vision.parent?.getProperty( + SolidMaterial.MATERIAL_KEY, + inherit = true, + includeStyles = false, + includeDefaults = false + ) + material = when { + ownMaterialMeta == null && stylesMaterialMeta == null && parentMaterialMeta == null -> { + //use default is not material properties are defined + ThreeMaterials.DEFAULT + } + ownMaterialMeta == null && parentMaterialMeta == null -> { + //If material is style-based, use cached + ThreeMaterials.cacheMeta(stylesMaterialMeta.node ?: Meta.EMPTY) + } + else -> { + val merge = sequenceOf(ownMaterialMeta, stylesMaterialMeta, parentMaterialMeta).merge().node ?: Meta.EMPTY + ThreeMaterials.buildMaterial(merge) + } + } +} + +public fun Mesh.updateMaterialProperty(vision: Vision, propertyName: Name) { + if (material.cached) { + //generate a new material since cached material should not be changed + updateMaterial(vision) + } else { + when (propertyName) { + SolidMaterial.MATERIAL_COLOR_KEY -> { + material.asDynamic().color = vision.getProperty( + SolidMaterial.MATERIAL_COLOR_KEY, + inherit = true, + includeStyles = true, + includeDefaults = false + )?.getColor() ?: ThreeMaterials.DEFAULT_COLOR + material.needsUpdate = true + } + SolidMaterial.MATERIAL_OPACITY_KEY -> { + val opacity = vision.getProperty( + SolidMaterial.MATERIAL_OPACITY_KEY, + inherit = true, + includeStyles = true, + includeDefaults = false + ).double ?: 1.0 + material.asDynamic().opacity = opacity + material.transparent = opacity < 1.0 + material.needsUpdate = true + } + SolidMaterial.MATERIAL_WIREFRAME_KEY -> { + material.asDynamic().wireframe = vision.getProperty( + SolidMaterial.MATERIAL_WIREFRAME_KEY, + inherit = true, + includeStyles = true, + includeDefaults = false + ).boolean ?: false + material.needsUpdate = true + } + else -> console.warn("Unrecognized material property: $propertyName") + } + } +} \ No newline at end of file diff --git a/visionforge-threejs/src/main/kotlin/info/laht/threekt/materials/Material.kt b/visionforge-threejs/src/main/kotlin/info/laht/threekt/materials/Material.kt index 3950c963..9a2b72d0 100644 --- a/visionforge-threejs/src/main/kotlin/info/laht/threekt/materials/Material.kt +++ b/visionforge-threejs/src/main/kotlin/info/laht/threekt/materials/Material.kt @@ -111,7 +111,7 @@ open external class Material { var visible: Boolean - var userData: Map + var userData: dynamic /** * Specifies that the material needs to be updated at the WebGL level. Set it to true if you made changes that need to be reflected in WebGL.