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