diff --git a/demo/sat-demo/src/main/kotlin/ru/mipt/npm/sat/satServer.kt b/demo/sat-demo/src/main/kotlin/ru/mipt/npm/sat/satServer.kt index 685970bd..bd7abf90 100644 --- a/demo/sat-demo/src/main/kotlin/ru/mipt/npm/sat/satServer.kt +++ b/demo/sat-demo/src/main/kotlin/ru/mipt/npm/sat/satServer.kt @@ -39,9 +39,10 @@ fun main() { val randomI = Random.nextInt(1, 4) val randomJ = Random.nextInt(1, 4) val target = "layer[$randomLayer].segment[$randomI,$randomJ]".toName() - (sat[target] as? Solid)?.color("red") + val targetVision = sat[target] as Solid + targetVision.color("red") delay(300) - (sat[target] as? Solid)?.color("green") + targetVision.color("green") delay(10) } } diff --git a/visionforge-core/src/commonMain/kotlin/hep/dataforge/vision/VisionBase.kt b/visionforge-core/src/commonMain/kotlin/hep/dataforge/vision/VisionBase.kt index 17f08888..94dbd2d8 100644 --- a/visionforge-core/src/commonMain/kotlin/hep/dataforge/vision/VisionBase.kt +++ b/visionforge-core/src/commonMain/kotlin/hep/dataforge/vision/VisionBase.kt @@ -11,8 +11,10 @@ import hep.dataforge.names.Name import hep.dataforge.names.asName import hep.dataforge.values.ValueType import hep.dataforge.vision.Vision.Companion.STYLE_KEY +import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.SharedFlow +import kotlinx.coroutines.launch import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable import kotlinx.serialization.Transient @@ -68,7 +70,7 @@ public open class VisionBase : Vision { yieldAll(getStyleItems(name)) } if (inherit ?: descriptor?.get(name)?.inherited == true) { - yield(parent?.getProperty(name, inherit)) + yield(parent?.getProperty(name, inherit, includeStyles, includeDefaults)) } yield(descriptor?.get(name)?.defaultItem()) }.merge() @@ -101,8 +103,9 @@ public open class VisionBase : Vision { if (propertyName == STYLE_KEY) { updateStyles(styles) } - - _propertyInvalidationFlow.tryEmit(propertyName) + GlobalScope.launch { + _propertyInvalidationFlow.emit(propertyName) + } } public fun configure(block: MutableMeta<*>.() -> Unit) { diff --git a/visionforge-core/src/commonMain/kotlin/hep/dataforge/vision/VisionGroupBase.kt b/visionforge-core/src/commonMain/kotlin/hep/dataforge/vision/VisionGroupBase.kt index 0bb40007..5162809e 100644 --- a/visionforge-core/src/commonMain/kotlin/hep/dataforge/vision/VisionGroupBase.kt +++ b/visionforge-core/src/commonMain/kotlin/hep/dataforge/vision/VisionGroupBase.kt @@ -1,8 +1,10 @@ package hep.dataforge.vision import hep.dataforge.names.* +import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.SharedFlow +import kotlinx.coroutines.launch import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable import kotlinx.serialization.Transient @@ -43,7 +45,9 @@ public open class VisionGroupBase : VisionBase(), MutableVisionGroup { * Propagate children change event upwards */ private fun childrenChanged(name: NameToken, before: Vision?, after: Vision?) { - _structureChanges.tryEmit(MutableVisionGroup.StructureChange(name, before, after)) + GlobalScope.launch { + _structureChanges.emit(MutableVisionGroup.StructureChange(name, before, after)) + } } /** diff --git a/visionforge-solid/src/commonMain/kotlin/hep/dataforge/vision/solid/SolidGroup.kt b/visionforge-solid/src/commonMain/kotlin/hep/dataforge/vision/solid/SolidGroup.kt index 355d2b7d..baf79443 100644 --- a/visionforge-solid/src/commonMain/kotlin/hep/dataforge/vision/solid/SolidGroup.kt +++ b/visionforge-solid/src/commonMain/kotlin/hep/dataforge/vision/solid/SolidGroup.kt @@ -16,7 +16,11 @@ import kotlinx.serialization.encoding.Encoder public interface PrototypeHolder { public val parent: VisionGroup? - public val prototypes: MutableVisionGroup? + + @VisionBuilder + public fun prototypes(builder: VisionContainerBuilder.() -> Unit) + + public fun getPrototype(name: Name): Solid? } /** @@ -28,18 +32,24 @@ public class SolidGroup : VisionGroupBase(), Solid, PrototypeHolder { override val descriptor: NodeDescriptor get() = Solid.descriptor + /** * A container for templates visible inside this group */ @Serializable(Prototypes.Companion::class) - override var prototypes: MutableVisionGroup? = null - private set + @SerialName("prototypes") + internal var prototypes: MutableVisionGroup? = null + + /** + * Ger a prototype redirecting the request to the parent if prototype is not found + */ + override fun getPrototype(name: Name): Solid? = + prototypes?.get(name) as? Solid ?: (parent as? PrototypeHolder)?.getPrototype(name) /** * Create or edit prototype node as a group */ - @VisionBuilder - public fun prototypes(builder: VisionContainerBuilder.() -> Unit): Unit { + override fun prototypes(builder: VisionContainerBuilder.() -> Unit): Unit { (prototypes ?: Prototypes().also { prototypes = it it.parent = this @@ -81,12 +91,6 @@ public fun SolidGroup(block: SolidGroup.() -> Unit): SolidGroup { return SolidGroup().apply(block) } -/** - * Ger a prototype redirecting the request to the parent if prototype is not found - */ -public tailrec fun PrototypeHolder.getPrototype(name: Name): Solid? = - prototypes?.get(name) as? Solid ?: (parent as? PrototypeHolder)?.getPrototype(name) - @VisionBuilder public fun VisionContainerBuilder.group( name: Name = Name.EMPTY, @@ -106,14 +110,12 @@ public fun VisionContainerBuilder.group(name: String, action: SolidGroup @Serializable(Prototypes.Companion::class) internal class Prototypes( children: Map = emptyMap(), -) : VisionGroupBase(), PrototypeHolder { +) : VisionGroupBase() { init { childrenInternal.putAll(children) } - override val prototypes: MutableVisionGroup get() = this - override fun attachChildren() { children.values.forEach { it.parent = parent @@ -131,7 +133,7 @@ internal class Prototypes( ): MetaItem<*>? = null override fun setProperty(name: Name, item: MetaItem<*>?, notify: Boolean) { - TODO("Not yet implemented") + error("Can't ser property of prototypes container") } override val descriptor: NodeDescriptor? = null diff --git a/visionforge-solid/src/commonMain/kotlin/hep/dataforge/vision/solid/SolidMaterial.kt b/visionforge-solid/src/commonMain/kotlin/hep/dataforge/vision/solid/SolidMaterial.kt index 7c69d283..e1f2c940 100644 --- a/visionforge-solid/src/commonMain/kotlin/hep/dataforge/vision/solid/SolidMaterial.kt +++ b/visionforge-solid/src/commonMain/kotlin/hep/dataforge/vision/solid/SolidMaterial.kt @@ -90,10 +90,20 @@ public class SolidMaterial : Scheme() { //must be lazy to avoid initialization bug NodeDescriptor { value(COLOR_KEY) { + inherited = true + usesStyles = true type(ValueType.STRING, ValueType.NUMBER) widgetType = "color" } +// value(SPECULAR_COLOR_KEY) { +// inherited = true +// usesStyles = true +// type(ValueType.STRING, ValueType.NUMBER) +// widgetType = "color" +// } value(OPACITY_KEY) { + inherited = true + usesStyles = true type(ValueType.NUMBER) default(1.0) attributes { @@ -104,6 +114,8 @@ public class SolidMaterial : Scheme() { widgetType = "slider" } value(WIREFRAME_KEY) { + inherited = true + usesStyles = true type(ValueType.BOOLEAN) default(false) } @@ -124,11 +136,7 @@ public var Solid.material: SolidMaterial? @VisionBuilder public fun Solid.material(builder: SolidMaterial.() -> Unit) { - val node = allProperties( - inherit = true, - includeStyles = true, - includeDefaults = true - ).getItem(MATERIAL_KEY).node + val node = allProperties(inherit = true).getItem(MATERIAL_KEY).node if (node != null) { SolidMaterial.update(node, builder) } else { diff --git a/visionforge-threejs/src/main/kotlin/hep/dataforge/vision/solid/three/ThreePlugin.kt b/visionforge-threejs/src/main/kotlin/hep/dataforge/vision/solid/three/ThreePlugin.kt index 2732d624..834a56a7 100644 --- a/visionforge-threejs/src/main/kotlin/hep/dataforge/vision/solid/three/ThreePlugin.kt +++ b/visionforge-threejs/src/main/kotlin/hep/dataforge/vision/solid/three/ThreePlugin.kt @@ -46,42 +46,41 @@ public class ThreePlugin : AbstractPlugin(), ElementVisionRenderer { as ThreeFactory? } - public fun buildObject3D(obj: Solid): Object3D { - return when (obj) { - is ThreeVision -> obj.render(this) - is SolidReferenceGroup -> ThreeReferenceFactory(this, obj) - is SolidGroup -> { - val group = ThreeGroup() - obj.children.forEach { (token, child) -> - if (child is Solid && child.ignore != true) { - try { - val object3D = buildObject3D(child) - group[token] = object3D - } catch (ex: Throwable) { - logger.error(ex) { "Failed to render $child" } - ex.printStackTrace() - } + public fun buildObject3D(obj: Solid): Object3D = when (obj) { + is ThreeVision -> obj.render(this) + is SolidReferenceGroup -> ThreeReferenceFactory(this, obj) + is SolidGroup -> { + val group = ThreeGroup() + obj.children.forEach { (token, child) -> + if (child is Solid && child.ignore != true) { + try { + val object3D = buildObject3D(child) + group[token] = object3D + } catch (ex: Throwable) { + logger.error(ex) { "Failed to render $child" } + ex.printStackTrace() } } + } - group.apply { - updatePosition(obj) - //obj.onChildrenChange() + group.apply { + updatePosition(obj) + //obj.onChildrenChange() - obj.propertyNameFlow.onEach { name -> - if ( - name.startsWith(Solid.POSITION_KEY) || - name.startsWith(Solid.ROTATION) || - name.startsWith(Solid.SCALE_KEY) - ) { - //update position of mesh using this object - updatePosition(obj) - } else if (name == Vision.VISIBLE_KEY) { - visible = obj.visible ?: true - } - }.launchIn(updateScope) + obj.propertyNameFlow.onEach { name -> + if ( + name.startsWith(Solid.POSITION_KEY) || + name.startsWith(Solid.ROTATION) || + name.startsWith(Solid.SCALE_KEY) + ) { + //update position of mesh using this object + updatePosition(obj) + } else if (name == Vision.VISIBLE_KEY) { + visible = obj.visible ?: true + } + }.launchIn(updateScope) - obj.structureChanges.onEach { (nameToken, _, child) -> + obj.structureChanges.onEach { (nameToken, _, child) -> // if (name.isEmpty()) { // logger.error { "Children change with empty name on $group" } // return@onChildrenChange @@ -90,32 +89,31 @@ public class ThreePlugin : AbstractPlugin(), ElementVisionRenderer { // val parentName = name.cutLast() // val childName = name.last()!! - //removing old object - findChild(nameToken.asName())?.let { oldChild -> - oldChild.parent?.remove(oldChild) - } + //removing old object + findChild(nameToken.asName())?.let { oldChild -> + oldChild.parent?.remove(oldChild) + } - //adding new object - if (child != null && child is Solid) { - try { - val object3D = buildObject3D(child) - set(nameToken, object3D) - } catch (ex: Throwable) { - logger.error(ex) { "Failed to render $child" } - } + //adding new object + if (child != null && child is Solid) { + try { + val object3D = buildObject3D(child) + set(nameToken, object3D) + } catch (ex: Throwable) { + logger.error(ex) { "Failed to render $child" } } - }.launchIn(updateScope) - } + } + }.launchIn(updateScope) } - is Composite -> compositeFactory(this, obj) - else -> { - //find specialized factory for this type if it is present - val factory: ThreeFactory? = findObjectFactory(obj::class) - when { - factory != null -> factory(this, obj) - obj is GeometrySolid -> ThreeShapeFactory(this, obj) - else -> error("Renderer for ${obj::class} not found") - } + } + is Composite -> compositeFactory(this, obj) + else -> { + //find specialized factory for this type if it is present + val factory: ThreeFactory? = findObjectFactory(obj::class) + when { + factory != null -> factory(this, obj) + obj is GeometrySolid -> ThreeShapeFactory(this, obj) + else -> error("Renderer for ${obj::class} not found") } } }