forked from kscience/visionforge
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
|
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 kotlinWrappersVersion by extra("pre.152-kotlin-1.4.32")
|
||||||
val fxVersion by extra("11")
|
val fxVersion by extra("11")
|
||||||
|
|
||||||
|
@ -23,7 +23,7 @@ private class ThreeDemoApp : Application {
|
|||||||
demo("dynamicBox", "Dancing boxes") {
|
demo("dynamicBox", "Dancing boxes") {
|
||||||
val boxes = (-10..10).flatMap { i ->
|
val boxes = (-10..10).flatMap { i ->
|
||||||
(-10..10).map { j ->
|
(-10..10).map { j ->
|
||||||
varBox(10, 10, 0, name = "cell_${i}_${j}") {
|
varBox(10, 10, name = "cell_${i}_${j}") {
|
||||||
x = i * 10
|
x = i * 10
|
||||||
y = j * 10
|
y = j * 10
|
||||||
value = 128
|
value = 128
|
||||||
|
@ -1,49 +1,37 @@
|
|||||||
package space.kscience.visionforge.solid.demo
|
package space.kscience.visionforge.solid.demo
|
||||||
|
|
||||||
import info.laht.threekt.core.BufferGeometry
|
|
||||||
import info.laht.threekt.core.Object3D
|
import info.laht.threekt.core.Object3D
|
||||||
import info.laht.threekt.geometries.BoxBufferGeometry
|
import info.laht.threekt.geometries.BoxBufferGeometry
|
||||||
import info.laht.threekt.objects.Mesh
|
import info.laht.threekt.objects.Mesh
|
||||||
import space.kscience.dataforge.meta.int
|
import space.kscience.dataforge.meta.int
|
||||||
import space.kscience.dataforge.meta.number
|
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.names.startsWith
|
||||||
import space.kscience.dataforge.values.asValue
|
import space.kscience.dataforge.values.asValue
|
||||||
import space.kscience.visionforge.getProperty
|
|
||||||
import space.kscience.visionforge.onPropertyChange
|
import space.kscience.visionforge.onPropertyChange
|
||||||
import space.kscience.visionforge.set
|
import space.kscience.visionforge.set
|
||||||
import space.kscience.visionforge.setProperty
|
import space.kscience.visionforge.setProperty
|
||||||
import space.kscience.visionforge.solid.*
|
import space.kscience.visionforge.solid.SolidGroup
|
||||||
import space.kscience.visionforge.solid.Solid.Companion.GEOMETRY_KEY
|
import space.kscience.visionforge.solid.layer
|
||||||
import space.kscience.visionforge.solid.three.*
|
import space.kscience.visionforge.solid.three.*
|
||||||
import kotlin.math.max
|
import kotlin.math.max
|
||||||
|
|
||||||
internal fun SolidGroup.varBox(
|
internal fun SolidGroup.varBox(
|
||||||
xSize: Number,
|
xSize: Number,
|
||||||
ySize: Number,
|
ySize: Number,
|
||||||
zSize: Number,
|
|
||||||
name: String = "",
|
name: String = "",
|
||||||
action: VariableBox.() -> Unit = {},
|
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() {
|
internal class VariableBox(val xSize: Number, val ySize: Number) : ThreeVision() {
|
||||||
init {
|
|
||||||
scaleX = xSize
|
|
||||||
scaleY = ySize
|
|
||||||
scaleZ = zSize
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun render(three: ThreePlugin): Object3D {
|
override fun render(three: ThreePlugin): Object3D {
|
||||||
val xSize = getProperty(X_SIZE_KEY, false).number?.toDouble() ?: 1.0
|
val geometry = BoxBufferGeometry(xSize, ySize, 1)
|
||||||
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)
|
|
||||||
|
|
||||||
//JS sometimes tries to pass Geometry as BufferGeometry
|
val material = ThreeMaterials.DEFAULT.clone()
|
||||||
@Suppress("USELESS_IS_CHECK") if (geometry !is BufferGeometry) error("BufferGeometry expected")
|
|
||||||
|
|
||||||
val mesh = Mesh(geometry, ThreeMaterials.DEFAULT).apply {
|
val mesh = Mesh(geometry, material).apply {
|
||||||
updateMaterial(this@VariableBox)
|
//updateMaterial(this@VariableBox)
|
||||||
applyEdges(this@VariableBox)
|
applyEdges(this@VariableBox)
|
||||||
//applyWireFrame(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)
|
it.layers.enable(this@VariableBox.layer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
mesh.scale.z = getOwnProperty(VALUE).number?.toDouble() ?: 1.0
|
||||||
mesh.scale.set(xSize, ySize, zSize)
|
|
||||||
|
|
||||||
//add listener to object properties
|
//add listener to object properties
|
||||||
onPropertyChange(three.context) { name ->
|
onPropertyChange(three.context) { name ->
|
||||||
when {
|
when {
|
||||||
name.startsWith(GEOMETRY_KEY) -> {
|
name == VALUE -> {
|
||||||
val newXSize = getProperty(X_SIZE_KEY, false).number?.toDouble() ?: 1.0
|
val value = getOwnProperty(VALUE).int ?: 0
|
||||||
val newYSize = getProperty(Y_SIZE_KEY, false).number?.toDouble() ?: 1.0
|
val size = value.toFloat() / 255f * 20f
|
||||||
val newZSize = getProperty(Z_SIZE_KEY, false).number?.toDouble() ?: 1.0
|
mesh.scale.z = size.toDouble()
|
||||||
mesh.scale.set(newXSize, newYSize, newZSize)
|
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()
|
mesh.updateMatrix()
|
||||||
}
|
}
|
||||||
name.startsWith(MeshThreeFactory.EDGES_KEY) -> mesh.applyEdges(this@VariableBox)
|
name.startsWith(MeshThreeFactory.EDGES_KEY) -> mesh.applyEdges(this@VariableBox)
|
||||||
//name.startsWith(MATERIAL_COLOR_KEY) -> mesh.updateMaterialProperty(this, name)
|
|
||||||
else -> mesh.updateProperty(this@VariableBox, name)
|
else -> mesh.updateProperty(this@VariableBox, name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -77,29 +68,17 @@ internal class VariableBox(xSize: Number, ySize: Number, zSize: Number) : ThreeV
|
|||||||
return mesh
|
return mesh
|
||||||
}
|
}
|
||||||
|
|
||||||
var variableZSize: Number
|
|
||||||
get() = getProperty(Z_SIZE_KEY, false).number ?: 0f
|
|
||||||
set(value) {
|
|
||||||
setProperty(Z_SIZE_KEY, value.asValue())
|
|
||||||
}
|
|
||||||
|
|
||||||
var value: Int
|
var value: Int
|
||||||
get() = getProperty("value", false).int ?: 0
|
get() = getOwnProperty(VALUE).int ?: 0
|
||||||
set(value) {
|
set(value) {
|
||||||
setProperty("value", value.asValue())
|
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())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private val X_SIZE_KEY = GEOMETRY_KEY + "xSize"
|
private val VALUE = "value".asName()
|
||||||
private val Y_SIZE_KEY = GEOMETRY_KEY + "ySize"
|
//
|
||||||
private val Z_SIZE_KEY = GEOMETRY_KEY + "zSize"
|
// 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 org.w3c.files.BlobPropertyBag
|
||||||
import react.*
|
import react.*
|
||||||
import react.dom.button
|
import react.dom.button
|
||||||
import space.kscience.dataforge.meta.descriptors.defaultMeta
|
|
||||||
import space.kscience.dataforge.meta.withDefault
|
import space.kscience.dataforge.meta.withDefault
|
||||||
import space.kscience.visionforge.react.flexColumn
|
import space.kscience.visionforge.react.flexColumn
|
||||||
import space.kscience.visionforge.react.flexRow
|
import space.kscience.visionforge.react.flexRow
|
||||||
@ -71,81 +70,9 @@ public val CanvasControls: FunctionalComponent<CanvasControlsProps> = functional
|
|||||||
}
|
}
|
||||||
propertyEditor(
|
propertyEditor(
|
||||||
ownProperties = props.canvas.options,
|
ownProperties = props.canvas.options,
|
||||||
allProperties = props.canvas.options.withDefault(Canvas3DOptions.descriptor.defaultMeta()),
|
allProperties = props.canvas.options.withDefault(Canvas3DOptions.descriptor.defaultMeta),
|
||||||
descriptor = Canvas3DOptions.descriptor,
|
descriptor = Canvas3DOptions.descriptor,
|
||||||
expanded = false
|
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.MetaItemValue
|
||||||
import space.kscience.dataforge.meta.descriptors.ItemDescriptor
|
import space.kscience.dataforge.meta.descriptors.ItemDescriptor
|
||||||
import space.kscience.dataforge.meta.descriptors.NodeDescriptor
|
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.descriptors.get
|
||||||
import space.kscience.dataforge.meta.get
|
import space.kscience.dataforge.meta.get
|
||||||
import space.kscience.dataforge.names.Name
|
import space.kscience.dataforge.names.Name
|
||||||
@ -43,7 +42,7 @@ private fun RBuilder.metaViewerItem(props: MetaViewerProps) {
|
|||||||
var expanded: Boolean by useState { true }
|
var expanded: Boolean by useState { true }
|
||||||
val item = props.root[props.name]
|
val item = props.root[props.name]
|
||||||
val descriptorItem: ItemDescriptor? = props.descriptor?.get(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"
|
val token = props.name.lastOrNull()?.toString() ?: "Meta"
|
||||||
|
|
||||||
|
@ -12,7 +12,6 @@ import react.dom.h2
|
|||||||
import ringui.island.ringIsland
|
import ringui.island.ringIsland
|
||||||
import ringui.tabs.ringSmartTabs
|
import ringui.tabs.ringSmartTabs
|
||||||
import ringui.tabs.ringTab
|
import ringui.tabs.ringTab
|
||||||
import space.kscience.dataforge.meta.descriptors.defaultMeta
|
|
||||||
import space.kscience.dataforge.meta.withDefault
|
import space.kscience.dataforge.meta.withDefault
|
||||||
import space.kscience.dataforge.names.Name
|
import space.kscience.dataforge.names.Name
|
||||||
import space.kscience.dataforge.names.isEmpty
|
import space.kscience.dataforge.names.isEmpty
|
||||||
@ -78,7 +77,7 @@ internal val CanvasControls: FunctionalComponent<CanvasControlsProps> = function
|
|||||||
}
|
}
|
||||||
propertyEditor(
|
propertyEditor(
|
||||||
ownProperties = props.canvas.options,
|
ownProperties = props.canvas.options,
|
||||||
allProperties = props.canvas.options.withDefault(Canvas3DOptions.descriptor.defaultMeta()),
|
allProperties = props.canvas.options.withDefault(Canvas3DOptions.descriptor.defaultMeta),
|
||||||
descriptor = Canvas3DOptions.descriptor,
|
descriptor = Canvas3DOptions.descriptor,
|
||||||
expanded = false
|
expanded = false
|
||||||
)
|
)
|
||||||
|
@ -98,8 +98,8 @@ public tailrec fun Vision.getStyle(name: String): Meta? =
|
|||||||
/**
|
/**
|
||||||
* Resolve an item in all style layers
|
* 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]
|
getStyle(it)[name]
|
||||||
}.filterNotNull()
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -10,8 +10,6 @@ import kotlinx.serialization.Serializable
|
|||||||
import kotlinx.serialization.Transient
|
import kotlinx.serialization.Transient
|
||||||
import space.kscience.dataforge.meta.*
|
import space.kscience.dataforge.meta.*
|
||||||
import space.kscience.dataforge.meta.descriptors.NodeDescriptor
|
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.misc.DFExperimental
|
||||||
import space.kscience.dataforge.names.Name
|
import space.kscience.dataforge.names.Name
|
||||||
import space.kscience.dataforge.names.asName
|
import space.kscience.dataforge.names.asName
|
||||||
@ -66,16 +64,16 @@ public open class VisionBase(
|
|||||||
): MetaItem? = if (!inherit && !includeStyles && !includeDefaults) {
|
): MetaItem? = if (!inherit && !includeStyles && !includeDefaults) {
|
||||||
getOwnProperty(name)
|
getOwnProperty(name)
|
||||||
} else {
|
} else {
|
||||||
sequence {
|
buildList {
|
||||||
yield(getOwnProperty(name))
|
add(getOwnProperty(name))
|
||||||
if (includeStyles) {
|
if (includeStyles) {
|
||||||
yieldAll(getStyleItems(name))
|
addAll(getStyleItems(name))
|
||||||
}
|
}
|
||||||
if (inherit) {
|
if (inherit) {
|
||||||
yield(parent?.getProperty(name, inherit, includeStyles, includeDefaults))
|
add(parent?.getProperty(name, inherit, includeStyles, includeDefaults))
|
||||||
}
|
}
|
||||||
if (includeDefaults) {
|
if (includeDefaults) {
|
||||||
yield(descriptor?.get(name)?.defaultItem())
|
add(descriptor?.defaultMeta?.get(name))
|
||||||
}
|
}
|
||||||
}.merge()
|
}.merge()
|
||||||
}
|
}
|
||||||
|
@ -6,12 +6,12 @@ import space.kscience.dataforge.values.asValue
|
|||||||
@DslMarker
|
@DslMarker
|
||||||
public annotation class VisionBuilder
|
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
|
null -> null
|
||||||
is MetaItemValue -> first //fast search for first entry if it is value
|
is MetaItemValue -> first //fast search for first entry if it is value
|
||||||
is MetaItemNode -> {
|
is MetaItemNode -> {
|
||||||
//merge nodes if first encountered node is meta
|
//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)
|
MetaItemNode(laminate)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,14 +20,14 @@ private fun SolidReference.getRefProperty(
|
|||||||
inherit: Boolean,
|
inherit: Boolean,
|
||||||
includeStyles: Boolean,
|
includeStyles: Boolean,
|
||||||
includeDefaults: Boolean,
|
includeDefaults: Boolean,
|
||||||
): MetaItem? = sequence {
|
): MetaItem? = buildList {
|
||||||
yield(getOwnProperty(name))
|
add(getOwnProperty(name))
|
||||||
if (includeStyles) {
|
if (includeStyles) {
|
||||||
yieldAll(getStyleItems(name))
|
addAll(getStyleItems(name))
|
||||||
}
|
}
|
||||||
yield(prototype.getProperty(name, inherit, includeStyles, includeDefaults))
|
add(prototype.getProperty(name, inherit, includeStyles, includeDefaults))
|
||||||
if (inherit) {
|
if (inherit) {
|
||||||
yield(parent?.getProperty(name, inherit))
|
add(parent?.getProperty(name, inherit))
|
||||||
}
|
}
|
||||||
}.merge()
|
}.merge()
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user