forked from kscience/visionforge
Fix (almost) property resolution
This commit is contained in:
parent
ecf4a6a198
commit
c586a2ea14
@ -49,7 +49,7 @@ fun main() {
|
||||
}
|
||||
|
||||
vision("form") { form }
|
||||
form.onPropertyChange {
|
||||
form.onPropertyChange { _, _ ->
|
||||
println(this)
|
||||
}
|
||||
}
|
||||
|
@ -59,6 +59,7 @@ internal class VariableBox(val xSize: Number, val ySize: Number) : ThreeJsVision
|
||||
material.color.setRGB(r.toFloat() / 256, g.toFloat() / 256, b.toFloat() / 256)
|
||||
mesh.updateMatrix()
|
||||
}
|
||||
|
||||
name.startsWith(ThreeMeshFactory.EDGES_KEY) -> mesh.applyEdges(this@VariableBox)
|
||||
else -> mesh.updateProperty(this@VariableBox, name)
|
||||
}
|
||||
|
@ -74,6 +74,8 @@ private fun RBuilder.propertyEditorItem(props: PropertyEditorProps) {
|
||||
val descriptor: MetaDescriptor? = useMemo(props.descriptor, props.name) { props.descriptor?.get(props.name) }
|
||||
var property: MutableMeta by useState { props.meta.getOrCreate(props.name) }
|
||||
|
||||
val defined = props.getPropertyState(props.name) == EditorPropertyState.Defined
|
||||
|
||||
val keys = useMemo(descriptor) {
|
||||
buildSet {
|
||||
descriptor?.children?.filterNot {
|
||||
@ -134,7 +136,7 @@ private fun RBuilder.propertyEditorItem(props: PropertyEditorProps) {
|
||||
styledSpan {
|
||||
css {
|
||||
+TreeStyles.treeLabel
|
||||
if (property.isEmpty()) {
|
||||
if (!defined) {
|
||||
+TreeStyles.treeLabelInactive
|
||||
}
|
||||
}
|
||||
@ -175,7 +177,7 @@ private fun RBuilder.propertyEditorItem(props: PropertyEditorProps) {
|
||||
}
|
||||
+"\u00D7"
|
||||
attrs {
|
||||
if (property.isEmpty()) {
|
||||
if (!defined) {
|
||||
disabled = true
|
||||
} else {
|
||||
onClickFunction = removeClick
|
||||
|
@ -1,5 +1,6 @@
|
||||
package space.kscience.visionforge.ring
|
||||
|
||||
import kotlinx.coroutines.DelicateCoroutinesApi
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.css.BorderStyle
|
||||
import kotlinx.css.Color
|
||||
@ -52,6 +53,7 @@ internal external interface CanvasControlsProps : Props {
|
||||
public var vision: Vision?
|
||||
}
|
||||
|
||||
@OptIn(DelicateCoroutinesApi::class)
|
||||
internal val CanvasControls: FC<CanvasControlsProps> = fc("CanvasControls") { props ->
|
||||
flexColumn {
|
||||
flexRow {
|
||||
|
@ -18,10 +18,10 @@ private tailrec fun styleIsDefined(vision: Vision, reference: StyleReference): B
|
||||
}
|
||||
|
||||
@VisionBuilder
|
||||
public fun Vision.useStyle(reference: StyleReference) {
|
||||
public fun Vision.useStyle(reference: StyleReference, notify: Boolean = true) {
|
||||
//check that style is defined in a parent
|
||||
//check(styleIsDefined(this, reference)) { "Style reference does not belong to a Vision parent" }
|
||||
useStyle(reference.name)
|
||||
useStyle(reference.name, notify)
|
||||
}
|
||||
|
||||
@VisionBuilder
|
||||
|
@ -83,10 +83,12 @@ public var Vision.styles: List<String>
|
||||
public val Vision.styleSheet: StyleSheet get() = StyleSheet(this)
|
||||
|
||||
/**
|
||||
* Add style name to the list of styles to be resolved later. The style with given name does not necessary exist at the moment.
|
||||
* Add style name to the list of styles to be resolved later.
|
||||
* The style with given name does not necessary exist at the moment.
|
||||
*/
|
||||
public fun Vision.useStyle(name: String) {
|
||||
styles = (properties.own?.get(Vision.STYLE_KEY)?.stringList ?: emptyList()) + name
|
||||
public fun Vision.useStyle(name: String, notify: Boolean = true) {
|
||||
val newStyle = properties.own?.get(Vision.STYLE_KEY)?.value?.list?.plus(name.asValue()) ?: listOf(name.asValue())
|
||||
properties.setValue(Vision.STYLE_KEY, newStyle.asValue(), notify)
|
||||
}
|
||||
|
||||
|
||||
|
@ -119,7 +119,7 @@ private fun CoroutineScope.collectChange(
|
||||
public fun Vision.flowChanges(
|
||||
collectionDuration: Duration,
|
||||
): Flow<VisionChange> = flow {
|
||||
val manager = manager?: error("Orphan vision could not collect changes")
|
||||
val manager = manager ?: error("Orphan vision could not collect changes")
|
||||
|
||||
var collector = VisionChangeBuilder(manager)
|
||||
coroutineScope {
|
||||
|
@ -61,23 +61,24 @@ public interface MutableVisionProperties : VisionProperties {
|
||||
includeStyles,
|
||||
)
|
||||
|
||||
|
||||
public fun setProperty(
|
||||
name: Name,
|
||||
node: Meta?,
|
||||
notify: Boolean = true,
|
||||
)
|
||||
|
||||
public fun setValue(
|
||||
name: Name,
|
||||
value: Value?,
|
||||
notify: Boolean = true,
|
||||
)
|
||||
}
|
||||
|
||||
public fun MutableVisionProperties.remove(name: Name){
|
||||
public fun MutableVisionProperties.remove(name: Name) {
|
||||
setProperty(name, null)
|
||||
}
|
||||
|
||||
public fun MutableVisionProperties.remove(name: String){
|
||||
public fun MutableVisionProperties.remove(name: String) {
|
||||
remove(name.parseAsName())
|
||||
}
|
||||
|
||||
@ -180,7 +181,7 @@ public abstract class AbstractVisionProperties(
|
||||
return descriptor?.defaultValue
|
||||
}
|
||||
|
||||
override fun setProperty(name: Name, node: Meta?) {
|
||||
override fun setProperty(name: Name, node: Meta?, notify: Boolean) {
|
||||
//TODO check old value?
|
||||
if (name.isEmpty()) {
|
||||
properties = node?.asMutableMeta()
|
||||
@ -189,25 +190,42 @@ public abstract class AbstractVisionProperties(
|
||||
} else {
|
||||
getOrCreateProperties().setMeta(name, node)
|
||||
}
|
||||
if (notify) {
|
||||
invalidate(name)
|
||||
}
|
||||
}
|
||||
|
||||
override fun setValue(name: Name, value: Value?) {
|
||||
override fun setValue(name: Name, value: Value?, notify: Boolean) {
|
||||
//TODO check old value?
|
||||
if (value == null) {
|
||||
properties?.getMeta(name)?.value = null
|
||||
} else {
|
||||
getOrCreateProperties().setValue(name, value)
|
||||
}
|
||||
if (notify) {
|
||||
invalidate(name)
|
||||
}
|
||||
}
|
||||
|
||||
@Transient
|
||||
private val _changes = MutableSharedFlow<Name>()
|
||||
override val changes: SharedFlow<Name> get() = _changes
|
||||
protected val changesInternal = MutableSharedFlow<Name>()
|
||||
override val changes: SharedFlow<Name> get() = changesInternal
|
||||
|
||||
@OptIn(DelicateCoroutinesApi::class)
|
||||
override fun invalidate(propertyName: Name) {
|
||||
//send update signal
|
||||
@OptIn(DelicateCoroutinesApi::class)
|
||||
(vision.manager?.context ?: GlobalScope).launch {
|
||||
changesInternal.emit(propertyName)
|
||||
}
|
||||
|
||||
//notify children if there are any
|
||||
if (vision is VisionGroup) {
|
||||
vision.children.values.forEach {
|
||||
it.properties.invalidate(propertyName)
|
||||
}
|
||||
}
|
||||
|
||||
// update styles
|
||||
if (propertyName == Vision.STYLE_KEY) {
|
||||
vision.styles.asSequence()
|
||||
.mapNotNull { vision.getStyle(it) }
|
||||
@ -217,9 +235,6 @@ public abstract class AbstractVisionProperties(
|
||||
invalidate(it.key.asName())
|
||||
}
|
||||
}
|
||||
(vision.manager?.context ?: GlobalScope).launch {
|
||||
_changes.emit(propertyName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -86,7 +86,9 @@ public abstract class VisionTagConsumer<R>(
|
||||
): T = div {
|
||||
id = resolveId(name)
|
||||
classes = setOf(OUTPUT_CLASS)
|
||||
if (vision.parent == null) {
|
||||
vision.setAsRoot(manager)
|
||||
}
|
||||
attributes[OUTPUT_NAME_ATTRIBUTE] = name.toString()
|
||||
if (!outputMeta.isEmpty()) {
|
||||
//Hard-code output configuration
|
||||
|
@ -37,7 +37,7 @@ public fun Vision.useProperty(
|
||||
includeStyles: Boolean? = null,
|
||||
scope: CoroutineScope? = manager?.context,
|
||||
callBack: (Meta) -> Unit,
|
||||
): Job = useProperty(propertyName.parseAsName(),inherit, includeStyles, scope, callBack)
|
||||
): Job = useProperty(propertyName.parseAsName(), inherit, includeStyles, scope, callBack)
|
||||
|
||||
public fun <V : Vision, T> V.useProperty(
|
||||
property: KProperty1<V, T>,
|
||||
|
@ -1,9 +1,7 @@
|
||||
package space.kscience.visionforge.meta
|
||||
|
||||
import kotlinx.coroutines.cancel
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.flow.collectIndexed
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import space.kscience.dataforge.context.Global
|
||||
import space.kscience.dataforge.context.fetch
|
||||
@ -20,6 +18,7 @@ private class TestScheme : Scheme() {
|
||||
companion object : SchemeSpec<TestScheme>(::TestScheme)
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
internal class VisionPropertyTest {
|
||||
|
||||
private val manager = Global.fetch(VisionManager)
|
||||
@ -68,56 +67,63 @@ internal class VisionPropertyTest {
|
||||
|
||||
val child = group.children["child"]!!
|
||||
|
||||
var value: Value? = null
|
||||
val deferred: CompletableDeferred<Value?> = CompletableDeferred()
|
||||
|
||||
var callCounter = 0
|
||||
|
||||
child.useProperty("test", inherit = true) {
|
||||
val subscription = child.useProperty("test", inherit = true) {
|
||||
deferred.complete(it.value)
|
||||
callCounter++
|
||||
value = it.value
|
||||
}
|
||||
|
||||
assertEquals(22, value?.int)
|
||||
assertEquals(22, deferred.await()?.int)
|
||||
assertEquals(1, callCounter)
|
||||
|
||||
child.properties.remove("test")
|
||||
|
||||
//Need this to avoid the race
|
||||
delay(20)
|
||||
|
||||
assertEquals(11, child.properties.getProperty("test", inherit = true).int)
|
||||
assertEquals(11, value?.int)
|
||||
assertEquals(2, callCounter)
|
||||
// assertEquals(11, deferred.await()?.int)
|
||||
// assertEquals(2, callCounter)
|
||||
subscription.cancel()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testChildrenPropertyFlow() = runTest(dispatchTimeoutMs = 200) {
|
||||
val group = Global.fetch(VisionManager).group {
|
||||
|
||||
properties {
|
||||
"test" put 11
|
||||
}
|
||||
|
||||
group("child") {
|
||||
properties {
|
||||
"test" put 22
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
val child = group.children["child"]!!
|
||||
|
||||
launch {
|
||||
child.flowPropertyValue("test", inherit = true).collectIndexed { index, value ->
|
||||
if (index == 0) {
|
||||
assertEquals(22, value?.int)
|
||||
} else if (index == 1) {
|
||||
assertEquals(11, value?.int)
|
||||
when (index) {
|
||||
0 -> assertEquals(22, value?.int)
|
||||
1 -> assertEquals(11, value?.int)
|
||||
2 -> {
|
||||
assertEquals(33, value?.int)
|
||||
cancel()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//wait for subscription to be created
|
||||
delay(10)
|
||||
delay(5)
|
||||
|
||||
child.properties.remove("test")
|
||||
|
||||
delay(50)
|
||||
group.properties["test"] = 33
|
||||
}
|
||||
}
|
@ -45,7 +45,7 @@ public class FX3DPlugin : AbstractPlugin() {
|
||||
}
|
||||
|
||||
public fun buildNode(obj: Solid): Node {
|
||||
val binding = VisualObjectFXBinding(this, obj)
|
||||
val binding = VisionFXBinding(this, obj)
|
||||
return when (obj) {
|
||||
is SolidReference -> referenceFactory(obj, binding)
|
||||
is SolidGroup -> {
|
||||
@ -150,7 +150,7 @@ public interface FX3DFactory<in T : Solid> {
|
||||
|
||||
public val type: KClass<in T>
|
||||
|
||||
public operator fun invoke(obj: T, binding: VisualObjectFXBinding): Node
|
||||
public operator fun invoke(obj: T, binding: VisionFXBinding): Node
|
||||
|
||||
public companion object {
|
||||
public const val TYPE: String = "fx3DFactory"
|
||||
|
@ -42,7 +42,7 @@ public class FXCompositeFactory(public val plugin: FX3DPlugin) : FX3DFactory<Com
|
||||
override val type: KClass<in Composite>
|
||||
get() = Composite::class
|
||||
|
||||
override fun invoke(obj: Composite, binding: VisualObjectFXBinding): Node {
|
||||
override fun invoke(obj: Composite, binding: VisionFXBinding): Node {
|
||||
val first = plugin.buildNode(obj.first) as? MeshView ?: error("Can't build node")
|
||||
val second = plugin.buildNode(obj.second) as? MeshView ?: error("Can't build node")
|
||||
val firstCSG = first.toCSG()
|
||||
|
@ -10,7 +10,7 @@ import kotlin.reflect.KClass
|
||||
public object FXConvexFactory : FX3DFactory<Convex> {
|
||||
override val type: KClass<in Convex> get() = Convex::class
|
||||
|
||||
override fun invoke(obj: Convex, binding: VisualObjectFXBinding): Node {
|
||||
override fun invoke(obj: Convex, binding: VisionFXBinding): Node {
|
||||
val hull = HullUtil.hull(
|
||||
obj.points.map { Vector3d.xyz(it.x.toDouble(), it.y.toDouble(), it.z.toDouble()) },
|
||||
PropertyStorage()
|
||||
|
@ -14,15 +14,17 @@ import kotlin.reflect.KClass
|
||||
public class FXReferenceFactory(public val plugin: FX3DPlugin) : FX3DFactory<SolidReference> {
|
||||
override val type: KClass<in SolidReference> get() = SolidReference::class
|
||||
|
||||
override fun invoke(obj: SolidReference, binding: VisualObjectFXBinding): Node {
|
||||
override fun invoke(obj: SolidReference, binding: VisionFXBinding): Node {
|
||||
val prototype = obj.prototype
|
||||
val node = plugin.buildNode(prototype)
|
||||
|
||||
obj.onPropertyChange { name->
|
||||
obj.onPropertyChange { name ->
|
||||
if (name.firstOrNull()?.body == REFERENCE_CHILD_PROPERTY_PREFIX) {
|
||||
val childName = name.firstOrNull()?.index?.let(Name::parse) ?: error("Wrong syntax for reference child property: '$name'")
|
||||
val childName = name.firstOrNull()?.index?.let(Name::parse)
|
||||
?: error("Wrong syntax for reference child property: '$name'")
|
||||
val propertyName = name.cutFirst()
|
||||
val referenceChild = obj.children.getChild(childName) ?: error("Reference child with name '$childName' not found")
|
||||
val referenceChild =
|
||||
obj.children.getChild(childName) ?: error("Reference child with name '$childName' not found")
|
||||
val child = node.findChild(childName) ?: error("Object child with name '$childName' not found")
|
||||
child.updateProperty(referenceChild, propertyName)
|
||||
}
|
||||
|
@ -11,7 +11,7 @@ import kotlin.reflect.KClass
|
||||
public object FXShapeFactory : FX3DFactory<GeometrySolid> {
|
||||
override val type: KClass<in GeometrySolid> get() = GeometrySolid::class
|
||||
|
||||
override fun invoke(obj: GeometrySolid, binding: VisualObjectFXBinding): MeshView {
|
||||
override fun invoke(obj: GeometrySolid, binding: VisionFXBinding): MeshView {
|
||||
val mesh = FXGeometryBuilder().apply { obj.toGeometry(this) }.build()
|
||||
return MeshView(mesh)
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ import tornadofx.*
|
||||
/**
|
||||
* A caching binding collection for [Vision] properties
|
||||
*/
|
||||
public class VisualObjectFXBinding(public val fx: FX3DPlugin, public val obj: Vision) {
|
||||
public class VisionFXBinding(public val fx: FX3DPlugin, public val obj: Vision) {
|
||||
private val bindings = HashMap<Name, ObjectBinding<Meta?>>()
|
||||
|
||||
init {
|
@ -30,7 +30,7 @@ public class GdmlLoaderOptions {
|
||||
styleCache.getOrPut(Name.parse(name)) {
|
||||
Meta(builder)
|
||||
}
|
||||
useStyle(name)
|
||||
useStyle(name, false)
|
||||
}
|
||||
|
||||
public fun Solid.transparent() {
|
||||
|
@ -352,7 +352,7 @@ private class GdmlLoader(val settings: GdmlLoaderOptions) {
|
||||
val rootStyle by final.style("gdml") {
|
||||
Solid.ROTATION_ORDER_KEY put RotationOrder.ZXY
|
||||
}
|
||||
final.useStyle(rootStyle)
|
||||
final.useStyle(rootStyle, false)
|
||||
|
||||
final.prototypes {
|
||||
proto.items.forEach { (token, item) ->
|
||||
|
@ -1,6 +1,9 @@
|
||||
package space.kscience.visionforge.solid
|
||||
|
||||
import kotlinx.coroutines.DelicateCoroutinesApi
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.flow.*
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.Transient
|
||||
@ -65,6 +68,25 @@ public class SolidReference(
|
||||
override fun getValue(name: Name, inherit: Boolean?, includeStyles: Boolean?): Value? {
|
||||
return properties?.getValue(name) ?: prototype.properties.getValue(name, inherit, includeStyles)
|
||||
}
|
||||
|
||||
override fun invalidate(propertyName: Name) {
|
||||
//send update signal
|
||||
@OptIn(DelicateCoroutinesApi::class)
|
||||
(manager?.context ?: GlobalScope).launch {
|
||||
changesInternal.emit(propertyName)
|
||||
}
|
||||
|
||||
// update styles
|
||||
if (propertyName == Vision.STYLE_KEY) {
|
||||
styles.asSequence()
|
||||
.mapNotNull { getStyle(it) }
|
||||
.flatMap { it.items.asSequence() }
|
||||
.distinctBy { it.key }
|
||||
.forEach {
|
||||
invalidate(it.key.asName())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -117,11 +139,11 @@ internal class SolidReferenceChild(
|
||||
includeStyles: Boolean?,
|
||||
): Value? = own.getValue(name) ?: prototype.properties.getValue(name, inherit, includeStyles)
|
||||
|
||||
override fun setProperty(name: Name, node: Meta?) {
|
||||
override fun setProperty(name: Name, node: Meta?, notify: Boolean) {
|
||||
own.setMeta(name, node)
|
||||
}
|
||||
|
||||
override fun setValue(name: Name, value: Value?) {
|
||||
override fun setValue(name: Name, value: Value?, notify: Boolean) {
|
||||
own.setValue(name, value)
|
||||
}
|
||||
|
||||
|
@ -2,6 +2,7 @@ package space.kscience.visionforge.solid
|
||||
|
||||
import kotlinx.coroutines.CompletableDeferred
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import space.kscience.dataforge.meta.int
|
||||
import space.kscience.dataforge.meta.string
|
||||
@ -10,8 +11,9 @@ import space.kscience.visionforge.*
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
@Suppress("UNUSED_VARIABLE")
|
||||
class PropertyTest {
|
||||
class SolidPropertyTest {
|
||||
@Test
|
||||
fun testColor() {
|
||||
val box = Box(10.0f, 10.0f, 10.0f)
|
||||
@ -23,7 +25,6 @@ class PropertyTest {
|
||||
assertEquals("pink", box.color.string)
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
@Test
|
||||
fun testColorUpdate() = runTest(dispatchTimeoutMs = 200) {
|
||||
val box = Box(10.0f, 10.0f, 10.0f)
|
||||
@ -31,11 +32,12 @@ class PropertyTest {
|
||||
val c = CompletableDeferred<String?>()
|
||||
|
||||
|
||||
val subscription = box.onPropertyChange(this) {
|
||||
if (it == SolidMaterial.MATERIAL_COLOR_KEY) {
|
||||
val subscription = box.onPropertyChange(this) { key ->
|
||||
if (key == SolidMaterial.MATERIAL_COLOR_KEY) {
|
||||
c.complete(box.color.string)
|
||||
}
|
||||
}
|
||||
delay(5)
|
||||
|
||||
box.material {
|
||||
color.set("pink")
|
@ -27,7 +27,7 @@ public object ThreeLabelFactory : ThreeFactory<SolidLabel> {
|
||||
return Mesh(textGeo, ThreeMaterials.DEFAULT).apply {
|
||||
updateMaterial(obj)
|
||||
updatePosition(obj)
|
||||
obj.onPropertyChange { _ ->
|
||||
obj.onPropertyChange {
|
||||
//TODO
|
||||
three.logger.warn { "Label parameter change not implemented" }
|
||||
}
|
||||
|
@ -43,7 +43,7 @@ public abstract class ThreeMeshFactory<in T : Solid>(
|
||||
}
|
||||
|
||||
//add listener to object properties
|
||||
obj.onPropertyChange { name ->
|
||||
obj.onPropertyChange { name->
|
||||
when {
|
||||
name.startsWith(Solid.GEOMETRY_KEY) -> {
|
||||
val oldGeometry = mesh.geometry
|
||||
|
@ -11,6 +11,7 @@ import space.kscience.dataforge.meta.update
|
||||
import space.kscience.dataforge.names.*
|
||||
import space.kscience.visionforge.ElementVisionRenderer
|
||||
import space.kscience.visionforge.Vision
|
||||
import space.kscience.visionforge.onPropertyChange
|
||||
import space.kscience.visionforge.solid.*
|
||||
import space.kscience.visionforge.solid.specifications.Canvas3DOptions
|
||||
import space.kscience.visionforge.visible
|
||||
@ -68,7 +69,7 @@ public class ThreePlugin : AbstractPlugin(), ElementVisionRenderer {
|
||||
updatePosition(obj)
|
||||
//obj.onChildrenChange()
|
||||
|
||||
obj.properties.changes.onEach { name ->
|
||||
obj.onPropertyChange(context) { name ->
|
||||
if (
|
||||
name.startsWith(Solid.POSITION_KEY) ||
|
||||
name.startsWith(Solid.ROTATION_KEY) ||
|
||||
@ -79,7 +80,7 @@ public class ThreePlugin : AbstractPlugin(), ElementVisionRenderer {
|
||||
} else if (name == Vision.VISIBLE_KEY) {
|
||||
visible = obj.visible ?: true
|
||||
}
|
||||
}.launchIn(context)
|
||||
}
|
||||
|
||||
obj.children.changes.onEach { childName ->
|
||||
val child = obj.children.getChild(childName)
|
||||
@ -101,6 +102,7 @@ public class ThreePlugin : AbstractPlugin(), ElementVisionRenderer {
|
||||
}.launchIn(context)
|
||||
}
|
||||
}
|
||||
|
||||
is Composite -> compositeFactory.build(this, obj)
|
||||
else -> {
|
||||
//find specialized factory for this type if it is present
|
||||
@ -179,6 +181,7 @@ internal fun Object3D.getOrCreateGroup(name: Name): Object3D {
|
||||
this.add(group)
|
||||
}
|
||||
}
|
||||
|
||||
else -> getOrCreateGroup(name.tokens.first().asName()).getOrCreateGroup(name.cutFirst())
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user