Improve dancing boxes performance. A lot.

This commit is contained in:
Alexander Nozik 2021-05-09 22:40:30 +03:00
parent b8fadb06b5
commit 5afa9117c4
10 changed files with 48 additions and 146 deletions

View File

@ -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")

View File

@ -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

View File

@ -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"
}
}

View File

@ -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<CanvasControlsProps> = 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)
}
}
}
}
}
}
}
*/
}
}

View File

@ -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"

View File

@ -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<CanvasControlsProps> = 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
)

View File

@ -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<MetaItem> = styles.asSequence().map {
public fun Vision.getStyleItems(name: Name): List<MetaItem> = styles.mapNotNull {
getStyle(it)[name]
}.filterNotNull()
}

View File

@ -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()
}

View File

@ -6,12 +6,12 @@ import space.kscience.dataforge.values.asValue
@DslMarker
public annotation class VisionBuilder
public fun Sequence<MetaItem?>.merge(): MetaItem? = when (val first = firstOrNull { it != null }) {
public fun List<MetaItem?>.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)
}
}

View File

@ -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")
}