Improve dancing boxes performance. A lot.
This commit is contained in:
parent
b8fadb06b5
commit
5afa9117c4
@ -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")
|
||||
|
||||
|
@ -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
|
||||
|
@ -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"
|
||||
}
|
||||
}
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
@ -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"
|
||||
|
||||
|
@ -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
|
||||
)
|
||||
|
@ -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()
|
||||
}
|
||||
|
||||
|
||||
|
@ -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()
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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()
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user