From 5afa9117c46a6ee9395a45178fa0292956cf7c3a Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Sun, 9 May 2021 22:40:30 +0300 Subject: [PATCH] Improve dancing boxes performance. A lot. --- build.gradle.kts | 2 +- .../visionforge/solid/demo/ThreeDemoApp.kt | 2 +- .../visionforge/solid/demo/VariableBox.kt | 75 +++++++------------ .../visionforge/bootstrap/outputConfig.kt | 75 +------------------ .../kscience/visionforge/react/MetaViewer.kt | 3 +- .../ringThreeControls.kt | 3 +- .../space/kscience/visionforge/StyleSheet.kt | 4 +- .../space/kscience/visionforge/VisionBase.kt | 12 ++- .../kotlin/space/kscience/visionforge/misc.kt | 4 +- .../visionforge/solid/SolidReference.kt | 14 ++-- 10 files changed, 48 insertions(+), 146 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 12596ced..9bdf18a6 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -7,7 +7,7 @@ plugins { id("ru.mipt.npm.gradle.js") apply false } -val dataforgeVersion by extra("0.4.0") +val dataforgeVersion by extra("0.4.1") val kotlinWrappersVersion by extra("pre.152-kotlin-1.4.32") val fxVersion by extra("11") diff --git a/demo/solid-showcase/src/jsMain/kotlin/space/kscience/visionforge/solid/demo/ThreeDemoApp.kt b/demo/solid-showcase/src/jsMain/kotlin/space/kscience/visionforge/solid/demo/ThreeDemoApp.kt index c5d2c2cf..db6ebbff 100644 --- a/demo/solid-showcase/src/jsMain/kotlin/space/kscience/visionforge/solid/demo/ThreeDemoApp.kt +++ b/demo/solid-showcase/src/jsMain/kotlin/space/kscience/visionforge/solid/demo/ThreeDemoApp.kt @@ -23,7 +23,7 @@ private class ThreeDemoApp : Application { demo("dynamicBox", "Dancing boxes") { val boxes = (-10..10).flatMap { i -> (-10..10).map { j -> - varBox(10, 10, 0, name = "cell_${i}_${j}") { + varBox(10, 10, name = "cell_${i}_${j}") { x = i * 10 y = j * 10 value = 128 diff --git a/demo/solid-showcase/src/jsMain/kotlin/space/kscience/visionforge/solid/demo/VariableBox.kt b/demo/solid-showcase/src/jsMain/kotlin/space/kscience/visionforge/solid/demo/VariableBox.kt index b6f0fd5c..e3961775 100644 --- a/demo/solid-showcase/src/jsMain/kotlin/space/kscience/visionforge/solid/demo/VariableBox.kt +++ b/demo/solid-showcase/src/jsMain/kotlin/space/kscience/visionforge/solid/demo/VariableBox.kt @@ -1,49 +1,37 @@ package space.kscience.visionforge.solid.demo -import info.laht.threekt.core.BufferGeometry import info.laht.threekt.core.Object3D import info.laht.threekt.geometries.BoxBufferGeometry import info.laht.threekt.objects.Mesh import space.kscience.dataforge.meta.int import space.kscience.dataforge.meta.number -import space.kscience.dataforge.names.plus +import space.kscience.dataforge.names.asName import space.kscience.dataforge.names.startsWith import space.kscience.dataforge.values.asValue -import space.kscience.visionforge.getProperty import space.kscience.visionforge.onPropertyChange import space.kscience.visionforge.set import space.kscience.visionforge.setProperty -import space.kscience.visionforge.solid.* -import space.kscience.visionforge.solid.Solid.Companion.GEOMETRY_KEY +import space.kscience.visionforge.solid.SolidGroup +import space.kscience.visionforge.solid.layer import space.kscience.visionforge.solid.three.* import kotlin.math.max internal fun SolidGroup.varBox( xSize: Number, ySize: Number, - zSize: Number, name: String = "", action: VariableBox.() -> Unit = {}, -): VariableBox = VariableBox(xSize, ySize, zSize).apply(action).also { set(name, it) } +): VariableBox = VariableBox(xSize, ySize).apply(action).also { set(name, it) } -internal class VariableBox(xSize: Number, ySize: Number, zSize: Number) : ThreeVision() { - init { - scaleX = xSize - scaleY = ySize - scaleZ = zSize - } +internal class VariableBox(val xSize: Number, val ySize: Number) : ThreeVision() { override fun render(three: ThreePlugin): Object3D { - val xSize = getProperty(X_SIZE_KEY, false).number?.toDouble() ?: 1.0 - val ySize = getProperty(Y_SIZE_KEY, false).number?.toDouble() ?: 1.0 - val zSize = getProperty(Z_SIZE_KEY, false).number?.toDouble() ?: 1.0 - val geometry = BoxBufferGeometry(1, 1, 1) + val geometry = BoxBufferGeometry(xSize, ySize, 1) - //JS sometimes tries to pass Geometry as BufferGeometry - @Suppress("USELESS_IS_CHECK") if (geometry !is BufferGeometry) error("BufferGeometry expected") + val material = ThreeMaterials.DEFAULT.clone() - val mesh = Mesh(geometry, ThreeMaterials.DEFAULT).apply { - updateMaterial(this@VariableBox) + val mesh = Mesh(geometry, material).apply { + //updateMaterial(this@VariableBox) applyEdges(this@VariableBox) //applyWireFrame(this@VariableBox) @@ -55,21 +43,24 @@ internal class VariableBox(xSize: Number, ySize: Number, zSize: Number) : ThreeV it.layers.enable(this@VariableBox.layer) } } - - mesh.scale.set(xSize, ySize, zSize) + mesh.scale.z = getOwnProperty(VALUE).number?.toDouble() ?: 1.0 //add listener to object properties onPropertyChange(three.context) { name -> when { - name.startsWith(GEOMETRY_KEY) -> { - val newXSize = getProperty(X_SIZE_KEY, false).number?.toDouble() ?: 1.0 - val newYSize = getProperty(Y_SIZE_KEY, false).number?.toDouble() ?: 1.0 - val newZSize = getProperty(Z_SIZE_KEY, false).number?.toDouble() ?: 1.0 - mesh.scale.set(newXSize, newYSize, newZSize) + name == VALUE -> { + val value = getOwnProperty(VALUE).int ?: 0 + val size = value.toFloat() / 255f * 20f + mesh.scale.z = size.toDouble() + mesh.position.z = size.toDouble() / 2 + + val b = max(0, 128 - value) + val r = max(0, value - 128) + val g = 255 - b - r + material.color.setRGB(r.toFloat() / 256, g.toFloat() / 256, b.toFloat() / 256) mesh.updateMatrix() } name.startsWith(MeshThreeFactory.EDGES_KEY) -> mesh.applyEdges(this@VariableBox) - //name.startsWith(MATERIAL_COLOR_KEY) -> mesh.updateMaterialProperty(this, name) else -> mesh.updateProperty(this@VariableBox, name) } } @@ -77,29 +68,17 @@ internal class VariableBox(xSize: Number, ySize: Number, zSize: Number) : ThreeV return mesh } - var variableZSize: Number - get() = getProperty(Z_SIZE_KEY, false).number ?: 0f - set(value) { - setProperty(Z_SIZE_KEY, value.asValue()) - } - var value: Int - get() = getProperty("value", false).int ?: 0 + get() = getOwnProperty(VALUE).int ?: 0 set(value) { - setProperty("value", value.asValue()) - val size = value.toFloat() / 255f * 20f - scaleZ = size - z = size / 2 - - val b = max(0, 128 - value) - val r = max(0, value - 128) - val g = 255 - b - r - color(r.toUByte(), g.toUByte(), b.toUByte()) + setProperty(VALUE, value.asValue()) } companion object { - private val X_SIZE_KEY = GEOMETRY_KEY + "xSize" - private val Y_SIZE_KEY = GEOMETRY_KEY + "ySize" - private val Z_SIZE_KEY = GEOMETRY_KEY + "zSize" + private val VALUE = "value".asName() +// +// private val X_SIZE_KEY = GEOMETRY_KEY + "xSize" +// private val Y_SIZE_KEY = GEOMETRY_KEY + "ySize" +// private val Z_SIZE_KEY = GEOMETRY_KEY + "zSize" } } \ No newline at end of file diff --git a/ui/bootstrap/src/main/kotlin/space/kscience/visionforge/bootstrap/outputConfig.kt b/ui/bootstrap/src/main/kotlin/space/kscience/visionforge/bootstrap/outputConfig.kt index b65b9666..accc68e2 100644 --- a/ui/bootstrap/src/main/kotlin/space/kscience/visionforge/bootstrap/outputConfig.kt +++ b/ui/bootstrap/src/main/kotlin/space/kscience/visionforge/bootstrap/outputConfig.kt @@ -11,7 +11,6 @@ import org.w3c.files.Blob import org.w3c.files.BlobPropertyBag import react.* import react.dom.button -import space.kscience.dataforge.meta.descriptors.defaultMeta import space.kscience.dataforge.meta.withDefault import space.kscience.visionforge.react.flexColumn import space.kscience.visionforge.react.flexRow @@ -71,81 +70,9 @@ public val CanvasControls: FunctionalComponent = functional } propertyEditor( ownProperties = props.canvas.options, - allProperties = props.canvas.options.withDefault(Canvas3DOptions.descriptor.defaultMeta()), + allProperties = props.canvas.options.withDefault(Canvas3DOptions.descriptor.defaultMeta), descriptor = Canvas3DOptions.descriptor, expanded = false ) - -/* h3 { +"Axes" } - flexRow { - css{ - border(1.px,BorderStyle.solid, Color.blue) - padding(4.px) - } - label("checkbox-inline") { - input(type = InputType.checkBox) { - attrs { - defaultChecked = props.canvas.options.axes.visible - onChangeFunction = { - props.canvas.options.axes.visible = (it.target as HTMLInputElement).checked - } - } - } - +"Axes" - } - } - h3 { +"Export" } - flexRow { - css{ - border(1.px,BorderStyle.solid, Color.blue) - padding(4.px) - } - button { - +"Export" - attrs { - onClickFunction = { - val json = (props.canvas.content as? SolidGroup)?.let { group -> - visionManager.encodeToString(group) - } - if (json != null) { - saveData(it, "object.json", "text/json") { - json - } - } - } - } - } - } - h3 { +"Layers" } - flexRow { - css { - flexWrap = FlexWrap.wrap - border(1.px,BorderStyle.solid, Color.blue) - padding(4.px) - } - (0..31).forEach { layer -> - styledDiv { - css{ - padding(4.px) - } - label { +layer.toString() } - input(type = InputType.checkBox) { - attrs { - if (layer == 0) { - defaultChecked = true - } - onChangeFunction = { - if ((it.target as HTMLInputElement).checked) { - props.canvas.camera.layers.enable(layer) - } else { - props.canvas.camera.layers.disable(layer) - } - } - } - } - } - } - } - */ } } \ No newline at end of file diff --git a/ui/react/src/main/kotlin/space/kscience/visionforge/react/MetaViewer.kt b/ui/react/src/main/kotlin/space/kscience/visionforge/react/MetaViewer.kt index 106ebd8b..58e651d8 100644 --- a/ui/react/src/main/kotlin/space/kscience/visionforge/react/MetaViewer.kt +++ b/ui/react/src/main/kotlin/space/kscience/visionforge/react/MetaViewer.kt @@ -9,7 +9,6 @@ import space.kscience.dataforge.meta.MetaItemNode import space.kscience.dataforge.meta.MetaItemValue import space.kscience.dataforge.meta.descriptors.ItemDescriptor import space.kscience.dataforge.meta.descriptors.NodeDescriptor -import space.kscience.dataforge.meta.descriptors.defaultItem import space.kscience.dataforge.meta.descriptors.get import space.kscience.dataforge.meta.get import space.kscience.dataforge.names.Name @@ -43,7 +42,7 @@ private fun RBuilder.metaViewerItem(props: MetaViewerProps) { var expanded: Boolean by useState { true } val item = props.root[props.name] val descriptorItem: ItemDescriptor? = props.descriptor?.get(props.name) - val actualItem = item ?: descriptorItem?.defaultItem() + val actualItem = item ?: descriptorItem?.defaultValue val token = props.name.lastOrNull()?.toString() ?: "Meta" diff --git a/ui/ring/src/main/kotlin/space.kscience.visionforge.ring/ringThreeControls.kt b/ui/ring/src/main/kotlin/space.kscience.visionforge.ring/ringThreeControls.kt index 63722265..431fc2d6 100644 --- a/ui/ring/src/main/kotlin/space.kscience.visionforge.ring/ringThreeControls.kt +++ b/ui/ring/src/main/kotlin/space.kscience.visionforge.ring/ringThreeControls.kt @@ -12,7 +12,6 @@ import react.dom.h2 import ringui.island.ringIsland import ringui.tabs.ringSmartTabs import ringui.tabs.ringTab -import space.kscience.dataforge.meta.descriptors.defaultMeta import space.kscience.dataforge.meta.withDefault import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.isEmpty @@ -78,7 +77,7 @@ internal val CanvasControls: FunctionalComponent = function } propertyEditor( ownProperties = props.canvas.options, - allProperties = props.canvas.options.withDefault(Canvas3DOptions.descriptor.defaultMeta()), + allProperties = props.canvas.options.withDefault(Canvas3DOptions.descriptor.defaultMeta), descriptor = Canvas3DOptions.descriptor, expanded = false ) 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 2e688667..655cb0f3 100644 --- a/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/StyleSheet.kt +++ b/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/StyleSheet.kt @@ -98,8 +98,8 @@ public tailrec fun Vision.getStyle(name: String): Meta? = /** * Resolve an item in all style layers */ -public fun Vision.getStyleItems(name: Name): Sequence = styles.asSequence().map { +public fun Vision.getStyleItems(name: Name): List = styles.mapNotNull { getStyle(it)[name] -}.filterNotNull() +} diff --git a/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/VisionBase.kt b/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/VisionBase.kt index 8b15493f..651de863 100644 --- a/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/VisionBase.kt +++ b/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/VisionBase.kt @@ -10,8 +10,6 @@ import kotlinx.serialization.Serializable import kotlinx.serialization.Transient import space.kscience.dataforge.meta.* import space.kscience.dataforge.meta.descriptors.NodeDescriptor -import space.kscience.dataforge.meta.descriptors.defaultItem -import space.kscience.dataforge.meta.descriptors.get import space.kscience.dataforge.misc.DFExperimental import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.asName @@ -66,16 +64,16 @@ public open class VisionBase( ): MetaItem? = if (!inherit && !includeStyles && !includeDefaults) { getOwnProperty(name) } else { - sequence { - yield(getOwnProperty(name)) + buildList { + add(getOwnProperty(name)) if (includeStyles) { - yieldAll(getStyleItems(name)) + addAll(getStyleItems(name)) } if (inherit) { - yield(parent?.getProperty(name, inherit, includeStyles, includeDefaults)) + add(parent?.getProperty(name, inherit, includeStyles, includeDefaults)) } if (includeDefaults) { - yield(descriptor?.get(name)?.defaultItem()) + add(descriptor?.defaultMeta?.get(name)) } }.merge() } diff --git a/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/misc.kt b/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/misc.kt index 8e51e537..f471b234 100644 --- a/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/misc.kt +++ b/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/misc.kt @@ -6,12 +6,12 @@ import space.kscience.dataforge.values.asValue @DslMarker public annotation class VisionBuilder -public fun Sequence.merge(): MetaItem? = when (val first = firstOrNull { it != null }) { +public fun List.merge(): MetaItem? = when (val first = firstOrNull { it != null }) { null -> null is MetaItemValue -> first //fast search for first entry if it is value is MetaItemNode -> { //merge nodes if first encountered node is meta - val laminate: Laminate = Laminate(mapNotNull { it.node }.toList()) + val laminate: Laminate = Laminate(mapNotNull { it.node }) MetaItemNode(laminate) } } diff --git a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/SolidReference.kt b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/SolidReference.kt index acb0ce88..d5d43100 100644 --- a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/SolidReference.kt +++ b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/SolidReference.kt @@ -20,14 +20,14 @@ private fun SolidReference.getRefProperty( inherit: Boolean, includeStyles: Boolean, includeDefaults: Boolean, -): MetaItem? = sequence { - yield(getOwnProperty(name)) +): MetaItem? = buildList { + add(getOwnProperty(name)) if (includeStyles) { - yieldAll(getStyleItems(name)) + addAll(getStyleItems(name)) } - yield(prototype.getProperty(name, inherit, includeStyles, includeDefaults)) + add(prototype.getProperty(name, inherit, includeStyles, includeDefaults)) if (inherit) { - yield(parent?.getProperty(name, inherit)) + add(parent?.getProperty(name, inherit)) } }.merge() @@ -45,8 +45,8 @@ public class SolidReferenceGroup( */ override val prototype: Solid get() { - if(parent == null) error("No parent is present for SolidReferenceGroup") - if(parent !is SolidGroup) error("Reference parent is not a group") + if (parent == null) error("No parent is present for SolidReferenceGroup") + if (parent !is SolidGroup) error("Reference parent is not a group") return (parent as? SolidGroup)?.getPrototype(refName) ?: error("Prototype with name $refName not found") }