forked from kscience/visionforge
Optimizations... optimizations
This commit is contained in:
parent
ac651c4d50
commit
e2f281debe
@ -91,7 +91,6 @@ private object RootDecoder {
|
|||||||
|
|
||||||
private fun <T> KSerializer<T>.unref(refCache: List<RefEntry>): KSerializer<T> = RootUnrefSerializer(this, refCache)
|
private fun <T> KSerializer<T>.unref(refCache: List<RefEntry>): KSerializer<T> = RootUnrefSerializer(this, refCache)
|
||||||
|
|
||||||
@OptIn(ExperimentalSerializationApi::class)
|
|
||||||
fun unrefSerializersModule(
|
fun unrefSerializersModule(
|
||||||
refCache: List<RefEntry>,
|
refCache: List<RefEntry>,
|
||||||
): SerializersModule = SerializersModule {
|
): SerializersModule = SerializersModule {
|
||||||
|
@ -21,21 +21,13 @@ kotlin {
|
|||||||
useCommonJs()
|
useCommonJs()
|
||||||
browser {
|
browser {
|
||||||
commonWebpackConfig {
|
commonWebpackConfig {
|
||||||
cssSupport.enabled = false
|
cssSupport {
|
||||||
|
enabled = false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
afterEvaluate {
|
|
||||||
val jsBrowserDistribution by tasks.getting
|
|
||||||
|
|
||||||
tasks.getByName<ProcessResources>("jvmProcessResources") {
|
|
||||||
dependsOn(jsBrowserDistribution)
|
|
||||||
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
|
|
||||||
from(jsBrowserDistribution)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sourceSets {
|
sourceSets {
|
||||||
commonMain {
|
commonMain {
|
||||||
dependencies {
|
dependencies {
|
||||||
@ -65,6 +57,23 @@ application {
|
|||||||
mainClass.set("ru.mipt.npm.muon.monitor.server.MMServerKt")
|
mainClass.set("ru.mipt.npm.muon.monitor.server.MMServerKt")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val jsBrowserDistribution by tasks.getting
|
||||||
|
val jsBrowserDevelopmentExecutableDistribution by tasks.getting
|
||||||
|
|
||||||
|
val devMode = rootProject.findProperty("visionforge.development") as? Boolean
|
||||||
|
?: rootProject.version.toString().contains("dev")
|
||||||
|
|
||||||
|
tasks.getByName<ProcessResources>("jvmProcessResources") {
|
||||||
|
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
|
||||||
|
if (devMode) {
|
||||||
|
dependsOn(jsBrowserDevelopmentExecutableDistribution)
|
||||||
|
from(jsBrowserDevelopmentExecutableDistribution)
|
||||||
|
} else {
|
||||||
|
dependsOn(jsBrowserDistribution)
|
||||||
|
from(jsBrowserDistribution)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//distributions {
|
//distributions {
|
||||||
// main {
|
// main {
|
||||||
// contents {
|
// contents {
|
||||||
|
@ -40,5 +40,5 @@ kotlin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
application {
|
application {
|
||||||
mainClassName = "space.kscience.visionforge.solid.demo.FXDemoAppKt"
|
mainClass.set("space.kscience.visionforge.solid.demo.FXDemoAppKt")
|
||||||
}
|
}
|
@ -20,7 +20,7 @@ fun VisionLayout<Solid>.demo(name: String, title: String = name, block: SolidGro
|
|||||||
}
|
}
|
||||||
val vision = solids.solidGroup {
|
val vision = solids.solidGroup {
|
||||||
block()
|
block()
|
||||||
ambientLight{
|
ambientLight {
|
||||||
color.set(Colors.white)
|
color.set(Colors.white)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
kotlin.code.style=official
|
kotlin.code.style=official
|
||||||
kotlin.mpp.stability.nowarn=true
|
kotlin.mpp.stability.nowarn=true
|
||||||
kotlin.jupyter.add.scanner=false
|
kotlin.jupyter.add.scanner=false
|
||||||
kotlin.incremental.js.ir=true
|
#kotlin.incremental.js.ir=true
|
||||||
|
|
||||||
org.gradle.parallel=true
|
org.gradle.parallel=true
|
||||||
org.gradle.jvmargs=-Xmx4G
|
org.gradle.jvmargs=-Xmx4G
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package space.kscience.visionforge.bootstrap
|
package space.kscience.visionforge.bootstrap
|
||||||
|
|
||||||
|
import kotlinx.coroutines.DelicateCoroutinesApi
|
||||||
import kotlinx.coroutines.GlobalScope
|
import kotlinx.coroutines.GlobalScope
|
||||||
import kotlinx.css.BorderStyle
|
import kotlinx.css.BorderStyle
|
||||||
import kotlinx.css.Color
|
import kotlinx.css.Color
|
||||||
@ -47,6 +48,7 @@ public external interface CanvasControlsProps : Props {
|
|||||||
public var vision: Vision?
|
public var vision: Vision?
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public val CanvasControls: FC<CanvasControlsProps> = fc("CanvasControls") { props ->
|
public val CanvasControls: FC<CanvasControlsProps> = fc("CanvasControls") { props ->
|
||||||
flexColumn {
|
flexColumn {
|
||||||
flexRow {
|
flexRow {
|
||||||
@ -68,6 +70,7 @@ public val CanvasControls: FC<CanvasControlsProps> = fc("CanvasControls") { prop
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@OptIn(DelicateCoroutinesApi::class)
|
||||||
propertyEditor(
|
propertyEditor(
|
||||||
scope = props.vision?.manager?.context ?: GlobalScope,
|
scope = props.vision?.manager?.context ?: GlobalScope,
|
||||||
properties = props.canvasOptions.meta,
|
properties = props.canvasOptions.meta,
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package space.kscience.visionforge.react
|
package space.kscience.visionforge.react
|
||||||
|
|
||||||
|
import info.laht.threekt.math.Color
|
||||||
import kotlinx.css.margin
|
import kotlinx.css.margin
|
||||||
import kotlinx.css.pct
|
import kotlinx.css.pct
|
||||||
import kotlinx.css.px
|
import kotlinx.css.px
|
||||||
@ -149,7 +150,7 @@ public val ColorValueChooser: FC<ValueChooserProps> = fc("ColorValueChooser") {
|
|||||||
attrs {
|
attrs {
|
||||||
this.value = props.value?.let { value ->
|
this.value = props.value?.let { value ->
|
||||||
if (value.type == ValueType.NUMBER) Colors.rgbToString(value.int)
|
if (value.type == ValueType.NUMBER) Colors.rgbToString(value.int)
|
||||||
else value.string
|
else "#" + Color(value.string).getHexString()
|
||||||
} ?: "#000000"
|
} ?: "#000000"
|
||||||
onChangeFunction = handleChange
|
onChangeFunction = handleChange
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@ import kotlinx.coroutines.flow.launchIn
|
|||||||
import kotlinx.coroutines.flow.onEach
|
import kotlinx.coroutines.flow.onEach
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
import space.kscience.dataforge.meta.*
|
import space.kscience.dataforge.meta.*
|
||||||
|
import space.kscience.dataforge.meta.descriptors.MetaDescriptor
|
||||||
import space.kscience.dataforge.names.Name
|
import space.kscience.dataforge.names.Name
|
||||||
import space.kscience.dataforge.names.plus
|
import space.kscience.dataforge.names.plus
|
||||||
import kotlin.jvm.Synchronized
|
import kotlin.jvm.Synchronized
|
||||||
@ -16,18 +17,37 @@ import kotlin.time.Duration
|
|||||||
* Create a deep copy of given Vision without external connections.
|
* Create a deep copy of given Vision without external connections.
|
||||||
*/
|
*/
|
||||||
private fun Vision.deepCopy(manager: VisionManager): Vision {
|
private fun Vision.deepCopy(manager: VisionManager): Vision {
|
||||||
|
if(this is NullVision) return NullVision
|
||||||
|
|
||||||
//Assuming that unrooted visions are already isolated
|
//Assuming that unrooted visions are already isolated
|
||||||
//TODO replace by efficient deep copy
|
//TODO replace by efficient deep copy
|
||||||
val json = manager.encodeToJsonElement(this)
|
val json = manager.encodeToJsonElement(this)
|
||||||
return manager.decodeFromJson(json)
|
return manager.decodeFromJson(json)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A vision used only in change propagation and showing that the target should be removed
|
||||||
|
*/
|
||||||
|
@Serializable
|
||||||
|
public object NullVision : Vision {
|
||||||
|
override var parent: Vision?
|
||||||
|
get() = null
|
||||||
|
set(_) {
|
||||||
|
error("Can't set parent for null vision")
|
||||||
|
}
|
||||||
|
|
||||||
|
override val properties: MutableVisionProperties get() = error("Can't get properties of `NullVision`")
|
||||||
|
|
||||||
|
override val descriptor: MetaDescriptor? = null
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An update for a [Vision]
|
* An update for a [Vision]
|
||||||
*/
|
*/
|
||||||
public class VisionChangeBuilder(private val manager: VisionManager) : MutableVisionContainer<Vision> {
|
public class VisionChangeBuilder(private val manager: VisionManager) : MutableVisionContainer<Vision> {
|
||||||
|
|
||||||
private var reset: Boolean = false
|
|
||||||
private var vision: Vision? = null
|
private var vision: Vision? = null
|
||||||
private val propertyChange = MutableMeta()
|
private val propertyChange = MutableMeta()
|
||||||
private val children: HashMap<Name, VisionChangeBuilder> = HashMap()
|
private val children: HashMap<Name, VisionChangeBuilder> = HashMap()
|
||||||
@ -50,8 +70,7 @@ public class VisionChangeBuilder(private val manager: VisionManager) : MutableVi
|
|||||||
override fun setChild(name: Name?, child: Vision?) {
|
override fun setChild(name: Name?, child: Vision?) {
|
||||||
if (name == null) error("Static children are not allowed in VisionChange")
|
if (name == null) error("Static children are not allowed in VisionChange")
|
||||||
getOrPutChild(name).apply {
|
getOrPutChild(name).apply {
|
||||||
vision = child
|
vision = child ?: NullVision
|
||||||
reset = vision == null
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -59,7 +78,6 @@ public class VisionChangeBuilder(private val manager: VisionManager) : MutableVi
|
|||||||
* Isolate collected changes by creating detached copies of given visions
|
* Isolate collected changes by creating detached copies of given visions
|
||||||
*/
|
*/
|
||||||
public fun deepCopy(): VisionChange = VisionChange(
|
public fun deepCopy(): VisionChange = VisionChange(
|
||||||
reset,
|
|
||||||
vision?.deepCopy(manager),
|
vision?.deepCopy(manager),
|
||||||
if (propertyChange.isEmpty()) null else propertyChange.seal(),
|
if (propertyChange.isEmpty()) null else propertyChange.seal(),
|
||||||
if (children.isEmpty()) null else children.mapValues { it.value.deepCopy() }
|
if (children.isEmpty()) null else children.mapValues { it.value.deepCopy() }
|
||||||
@ -67,14 +85,12 @@ public class VisionChangeBuilder(private val manager: VisionManager) : MutableVi
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param delete flag showing that this vision child should be removed
|
* @param vision a new value for vision content. If the Vision is to be removed should be [NullVision]
|
||||||
* @param vision a new value for vision content
|
|
||||||
* @param properties updated properties
|
* @param properties updated properties
|
||||||
* @param children a map of children changed in ths [VisionChange]. If a child to be removed, set [delete] flag to true.
|
* @param children a map of children changed in ths [VisionChange]. If a child to be removed, set [delete] flag to true.
|
||||||
*/
|
*/
|
||||||
@Serializable
|
@Serializable
|
||||||
public data class VisionChange(
|
public data class VisionChange(
|
||||||
public val delete: Boolean = false,
|
|
||||||
public val vision: Vision? = null,
|
public val vision: Vision? = null,
|
||||||
public val properties: Meta? = null,
|
public val properties: Meta? = null,
|
||||||
public val children: Map<Name, VisionChange>? = null,
|
public val children: Map<Name, VisionChange>? = null,
|
||||||
|
@ -5,6 +5,7 @@ import kotlinx.coroutines.Job
|
|||||||
import kotlinx.coroutines.flow.*
|
import kotlinx.coroutines.flow.*
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import space.kscience.dataforge.names.*
|
import space.kscience.dataforge.names.*
|
||||||
|
import space.kscience.visionforge.VisionChildren.Companion.STATIC_TOKEN_BODY
|
||||||
import kotlin.jvm.Synchronized
|
import kotlin.jvm.Synchronized
|
||||||
|
|
||||||
@DslMarker
|
@DslMarker
|
||||||
@ -40,6 +41,8 @@ public interface VisionChildren : VisionContainer<Vision> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public companion object {
|
public companion object {
|
||||||
|
public const val STATIC_TOKEN_BODY: String = "@static"
|
||||||
|
|
||||||
public fun empty(owner: Vision): VisionChildren = object : VisionChildren {
|
public fun empty(owner: Vision): VisionChildren = object : VisionChildren {
|
||||||
override val group: Vision get() = owner
|
override val group: Vision get() = owner
|
||||||
override val keys: Set<NameToken> get() = emptySet()
|
override val keys: Set<NameToken> get() = emptySet()
|
||||||
@ -105,8 +108,8 @@ public operator fun MutableVisionChildren.set(name: String?, vision: Vision?) {
|
|||||||
/**
|
/**
|
||||||
* Add a static child. Statics could not be found by name, removed or replaced. Changing statics also do not trigger events.
|
* Add a static child. Statics could not be found by name, removed or replaced. Changing statics also do not trigger events.
|
||||||
*/
|
*/
|
||||||
public fun MutableVisionChildren.static(child: Vision): Unit {
|
public fun MutableVisionChildren.static(child: Vision) {
|
||||||
set(NameToken("@static", index = child.hashCode().toString()), child)
|
set(NameToken(STATIC_TOKEN_BODY, index = child.hashCode().toString()), child)
|
||||||
}
|
}
|
||||||
|
|
||||||
public fun VisionChildren.asSequence(): Sequence<Pair<NameToken, Vision>> = sequence {
|
public fun VisionChildren.asSequence(): Sequence<Pair<NameToken, Vision>> = sequence {
|
||||||
@ -185,14 +188,14 @@ internal abstract class VisionChildrenImpl(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun clear() {
|
override fun clear() {
|
||||||
if (!items.isNullOrEmpty()) {
|
items?.forEach { set(it.key, null) }
|
||||||
updateJobs.values.forEach {
|
// if (!items.isNullOrEmpty()) {
|
||||||
it.cancel()
|
// updateJobs.values.forEach {
|
||||||
}
|
// it.cancel()
|
||||||
updateJobs.clear()
|
// }
|
||||||
items?.clear()
|
// updateJobs.clear()
|
||||||
onChange(Name.EMPTY)
|
// items?.clear()
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//
|
//
|
||||||
|
@ -35,7 +35,7 @@ public abstract class AbstractVisionGroup : AbstractVision(), MutableVisionGroup
|
|||||||
override fun update(change: VisionChange) {
|
override fun update(change: VisionChange) {
|
||||||
change.children?.forEach { (name, change) ->
|
change.children?.forEach { (name, change) ->
|
||||||
when {
|
when {
|
||||||
change.delete -> children.setChild(name, null)
|
change.vision == NullVision -> children.setChild(name, null)
|
||||||
change.vision != null -> children.setChild(name, change.vision)
|
change.vision != null -> children.setChild(name, change.vision)
|
||||||
else -> children.getChild(name)?.update(change)
|
else -> children.getChild(name)?.update(change)
|
||||||
}
|
}
|
||||||
|
@ -73,6 +73,7 @@ public class VisionManager(meta: Meta) : AbstractPlugin(meta), MutableVisionCont
|
|||||||
private val defaultSerialModule: SerializersModule = SerializersModule {
|
private val defaultSerialModule: SerializersModule = SerializersModule {
|
||||||
polymorphic(Vision::class) {
|
polymorphic(Vision::class) {
|
||||||
default { SimpleVisionGroup.serializer() }
|
default { SimpleVisionGroup.serializer() }
|
||||||
|
subclass(NullVision.serializer())
|
||||||
subclass(SimpleVisionGroup.serializer())
|
subclass(SimpleVisionGroup.serializer())
|
||||||
subclass(VisionOfNumberField.serializer())
|
subclass(VisionOfNumberField.serializer())
|
||||||
subclass(VisionOfTextField.serializer())
|
subclass(VisionOfTextField.serializer())
|
||||||
|
@ -115,7 +115,7 @@ public interface Solid : Vision {
|
|||||||
public var Solid.layer: Int
|
public var Solid.layer: Int
|
||||||
get() = properties.getValue(LAYER_KEY, inherit = true)?.int ?: 0
|
get() = properties.getValue(LAYER_KEY, inherit = true)?.int ?: 0
|
||||||
set(value) {
|
set(value) {
|
||||||
properties.set(LAYER_KEY, value)
|
properties[LAYER_KEY] = value
|
||||||
}
|
}
|
||||||
|
|
||||||
// Common properties
|
// Common properties
|
||||||
|
@ -186,7 +186,7 @@ internal class SolidReferenceChild(
|
|||||||
override fun update(change: VisionChange) {
|
override fun update(change: VisionChange) {
|
||||||
change.children?.forEach { (name, change) ->
|
change.children?.forEach { (name, change) ->
|
||||||
when {
|
when {
|
||||||
change.delete -> error("Deleting children inside ref is not allowed.")
|
change.vision == NullVision -> error("Deleting children inside ref is not allowed.")
|
||||||
change.vision != null -> error("Updating content of the ref is not allowed")
|
change.vision != null -> error("Updating content of the ref is not allowed")
|
||||||
else -> children.getChild(name)?.update(change)
|
else -> children.getChild(name)?.update(change)
|
||||||
}
|
}
|
||||||
|
@ -8,10 +8,10 @@ import kotlin.reflect.KClass
|
|||||||
public object ThreeAmbientLightFactory : ThreeFactory<AmbientLightSource> {
|
public object ThreeAmbientLightFactory : ThreeFactory<AmbientLightSource> {
|
||||||
override val type: KClass<in AmbientLightSource> get() = AmbientLightSource::class
|
override val type: KClass<in AmbientLightSource> get() = AmbientLightSource::class
|
||||||
|
|
||||||
override fun build(three: ThreePlugin, obj: AmbientLightSource): AmbientLight {
|
override fun build(three: ThreePlugin, vision: AmbientLightSource, observe: Boolean): AmbientLight {
|
||||||
val res = AmbientLight().apply {
|
val res = AmbientLight().apply {
|
||||||
color = obj.color.threeColor() ?: Color(0x404040)
|
color = vision.color.threeColor() ?: Color(0x404040)
|
||||||
intensity = obj.intensity.toDouble()
|
intensity = vision.intensity.toDouble()
|
||||||
}
|
}
|
||||||
|
|
||||||
return res
|
return res
|
||||||
|
@ -22,17 +22,17 @@ import kotlin.reflect.KClass
|
|||||||
public object ThreeCanvasLabelFactory : ThreeFactory<SolidLabel> {
|
public object ThreeCanvasLabelFactory : ThreeFactory<SolidLabel> {
|
||||||
override val type: KClass<in SolidLabel> get() = SolidLabel::class
|
override val type: KClass<in SolidLabel> get() = SolidLabel::class
|
||||||
|
|
||||||
override fun build(three: ThreePlugin, obj: SolidLabel): Object3D {
|
override fun build(three: ThreePlugin, vision: SolidLabel, observe: Boolean): Object3D {
|
||||||
val canvas = document.createElement("canvas") as HTMLCanvasElement
|
val canvas = document.createElement("canvas") as HTMLCanvasElement
|
||||||
val context = canvas.getContext("2d") as CanvasRenderingContext2D
|
val context = canvas.getContext("2d") as CanvasRenderingContext2D
|
||||||
context.font = "Bold ${obj.fontSize}pt ${obj.fontFamily}"
|
context.font = "Bold ${vision.fontSize}pt ${vision.fontFamily}"
|
||||||
context.fillStyle = obj.properties.getValue(SolidMaterial.MATERIAL_COLOR_KEY, false, true)?.value ?: "black"
|
context.fillStyle = vision.properties.getValue(SolidMaterial.MATERIAL_COLOR_KEY, false, true)?.value ?: "black"
|
||||||
context.textBaseline = CanvasTextBaseline.MIDDLE
|
context.textBaseline = CanvasTextBaseline.MIDDLE
|
||||||
val metrics = context.measureText(obj.text)
|
val metrics = context.measureText(vision.text)
|
||||||
//canvas.width = metrics.width.toInt()
|
//canvas.width = metrics.width.toInt()
|
||||||
|
|
||||||
|
|
||||||
context.fillText(obj.text, (canvas.width - metrics.width) / 2, 0.5 * canvas.height)
|
context.fillText(vision.text, (canvas.width - metrics.width) / 2, 0.5 * canvas.height)
|
||||||
|
|
||||||
|
|
||||||
// canvas contents will be used for a texture
|
// canvas contents will be used for a texture
|
||||||
@ -50,7 +50,7 @@ public object ThreeCanvasLabelFactory : ThreeFactory<SolidLabel> {
|
|||||||
material
|
material
|
||||||
)
|
)
|
||||||
|
|
||||||
mesh.updatePosition(obj)
|
mesh.updatePosition(vision)
|
||||||
|
|
||||||
mesh.userData[DO_NOT_HIGHLIGHT_TAG] = true
|
mesh.userData[DO_NOT_HIGHLIGHT_TAG] = true
|
||||||
return mesh
|
return mesh
|
||||||
|
@ -37,21 +37,25 @@ public class ThreeCompositeFactory(public val three: ThreePlugin) : ThreeFactory
|
|||||||
|
|
||||||
override val type: KClass<in Composite> get() = Composite::class
|
override val type: KClass<in Composite> get() = Composite::class
|
||||||
|
|
||||||
override fun build(three: ThreePlugin, obj: Composite): Mesh {
|
override fun build(three: ThreePlugin, vision: Composite, observe: Boolean): Mesh {
|
||||||
val first = three.buildObject3D(obj.first).takeIfMesh() ?: error("First part of composite is not a mesh")
|
val first =
|
||||||
val second = three.buildObject3D(obj.second).takeIfMesh() ?: error("Second part of composite is not a mesh")
|
three.buildObject3D(vision.first, observe).takeIfMesh() ?: error("First part of composite is not a mesh")
|
||||||
return when (obj.compositeType) {
|
val second =
|
||||||
|
three.buildObject3D(vision.second, observe).takeIfMesh() ?: error("Second part of composite is not a mesh")
|
||||||
|
return when (vision.compositeType) {
|
||||||
CompositeType.GROUP, CompositeType.UNION -> CSG.union(first, second)
|
CompositeType.GROUP, CompositeType.UNION -> CSG.union(first, second)
|
||||||
CompositeType.INTERSECT -> CSG.intersect(first, second)
|
CompositeType.INTERSECT -> CSG.intersect(first, second)
|
||||||
CompositeType.SUBTRACT -> CSG.subtract(first, second)
|
CompositeType.SUBTRACT -> CSG.subtract(first, second)
|
||||||
}.apply {
|
}.apply {
|
||||||
updatePosition(obj)
|
updatePosition(vision)
|
||||||
applyProperties(obj)
|
applyProperties(vision)
|
||||||
obj.onPropertyChange { name ->
|
if (observe) {
|
||||||
when {
|
vision.onPropertyChange { name ->
|
||||||
//name.startsWith(WIREFRAME_KEY) -> mesh.applyWireFrame(obj)
|
when {
|
||||||
name.startsWith(ThreeMeshFactory.EDGES_KEY) -> applyEdges(obj)
|
//name.startsWith(WIREFRAME_KEY) -> mesh.applyWireFrame(obj)
|
||||||
else -> updateProperty(obj, name)
|
name.startsWith(ThreeMeshFactory.EDGES_KEY) -> applyEdges(vision)
|
||||||
|
else -> updateProperty(vision, name)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,11 @@ public interface ThreeFactory<in T : Vision> {
|
|||||||
|
|
||||||
public val type: KClass<in T>
|
public val type: KClass<in T>
|
||||||
|
|
||||||
public fun build(three: ThreePlugin, obj: T): Object3D
|
/**
|
||||||
|
* Build an [Object3D] from [vision].
|
||||||
|
* @param observe if false, does not observe the changes in [vision] after render (useful for statics).
|
||||||
|
*/
|
||||||
|
public fun build(three: ThreePlugin, vision: T, observe: Boolean = true): Object3D
|
||||||
|
|
||||||
public companion object {
|
public companion object {
|
||||||
public const val TYPE: String = "threeFactory"
|
public const val TYPE: String = "threeFactory"
|
||||||
@ -32,10 +36,10 @@ public interface ThreeFactory<in T : Vision> {
|
|||||||
/**
|
/**
|
||||||
* Update position, rotation and visibility
|
* Update position, rotation and visibility
|
||||||
*/
|
*/
|
||||||
public fun Object3D.updatePosition(obj: Vision) {
|
public fun Object3D.updatePosition(vision: Vision) {
|
||||||
visible = obj.visible ?: true
|
visible = vision.visible ?: true
|
||||||
if (obj is Solid) {
|
if (vision is Solid) {
|
||||||
position.set(obj.x, obj.y, obj.z)
|
position.set(vision.x, vision.y, vision.z)
|
||||||
|
|
||||||
// val quaternion = obj.quaternion
|
// val quaternion = obj.quaternion
|
||||||
//
|
//
|
||||||
@ -46,9 +50,9 @@ public fun Object3D.updatePosition(obj: Vision) {
|
|||||||
// setRotationFromEuler( Euler(obj.rotationX, obj.rotationY, obj.rotationZ, obj.rotationOrder.name))
|
// setRotationFromEuler( Euler(obj.rotationX, obj.rotationY, obj.rotationZ, obj.rotationOrder.name))
|
||||||
// }
|
// }
|
||||||
|
|
||||||
setRotationFromEuler( Euler(obj.rotationX, obj.rotationY, obj.rotationZ, obj.rotationOrder.name))
|
setRotationFromEuler( Euler(vision.rotationX, vision.rotationY, vision.rotationZ, vision.rotationOrder.name))
|
||||||
|
|
||||||
scale.set(obj.scaleX, obj.scaleY, obj.scaleZ)
|
scale.set(vision.scaleX, vision.scaleY, vision.scaleZ)
|
||||||
updateMatrix()
|
updateMatrix()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,19 +17,21 @@ import kotlin.reflect.KClass
|
|||||||
public object ThreeLabelFactory : ThreeFactory<SolidLabel> {
|
public object ThreeLabelFactory : ThreeFactory<SolidLabel> {
|
||||||
override val type: KClass<in SolidLabel> get() = SolidLabel::class
|
override val type: KClass<in SolidLabel> get() = SolidLabel::class
|
||||||
|
|
||||||
override fun build(three: ThreePlugin, obj: SolidLabel): Object3D {
|
override fun build(three: ThreePlugin, vision: SolidLabel, observe: Boolean): Object3D {
|
||||||
val textGeo = TextBufferGeometry(obj.text, jso {
|
val textGeo = TextBufferGeometry(vision.text, jso {
|
||||||
font = obj.fontFamily
|
font = vision.fontFamily
|
||||||
size = 20
|
size = 20
|
||||||
height = 1
|
height = 1
|
||||||
curveSegments = 1
|
curveSegments = 1
|
||||||
})
|
})
|
||||||
return Mesh(textGeo, ThreeMaterials.DEFAULT).apply {
|
return Mesh(textGeo, ThreeMaterials.DEFAULT).apply {
|
||||||
updateMaterial(obj)
|
createMaterial(vision)
|
||||||
updatePosition(obj)
|
updatePosition(vision)
|
||||||
obj.onPropertyChange {
|
if(observe) {
|
||||||
//TODO
|
vision.onPropertyChange(three.context) {
|
||||||
three.logger.warn { "Label parameter change not implemented" }
|
//TODO
|
||||||
|
three.logger.warn { "Label parameter change not implemented" }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,27 +16,29 @@ import kotlin.reflect.KClass
|
|||||||
public object ThreeLineFactory : ThreeFactory<PolyLine> {
|
public object ThreeLineFactory : ThreeFactory<PolyLine> {
|
||||||
override val type: KClass<PolyLine> get() = PolyLine::class
|
override val type: KClass<PolyLine> get() = PolyLine::class
|
||||||
|
|
||||||
override fun build(three: ThreePlugin, obj: PolyLine): Object3D {
|
override fun build(three: ThreePlugin, vision: PolyLine, observe: Boolean): Object3D {
|
||||||
val geometry = BufferGeometry().apply {
|
val geometry = BufferGeometry().apply {
|
||||||
setFromPoints(Array((obj.points.size - 1) * 2) {
|
setFromPoints(Array((vision.points.size - 1) * 2) {
|
||||||
obj.points[ceil(it / 2.0).toInt()].toVector()
|
vision.points[ceil(it / 2.0).toInt()].toVector()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
val material = ThreeMaterials.getLineMaterial(
|
val material = ThreeMaterials.getLineMaterial(
|
||||||
obj.properties.getProperty(SolidMaterial.MATERIAL_KEY),
|
vision.properties.getProperty(SolidMaterial.MATERIAL_KEY),
|
||||||
false
|
false
|
||||||
)
|
)
|
||||||
|
|
||||||
material.linewidth = obj.thickness.toDouble()
|
material.linewidth = vision.thickness.toDouble()
|
||||||
material.color = obj.color.string?.let { Color(it) } ?: DEFAULT_LINE_COLOR
|
material.color = vision.color.string?.let { Color(it) } ?: DEFAULT_LINE_COLOR
|
||||||
|
|
||||||
return LineSegments(geometry, material).apply {
|
return LineSegments(geometry, material).apply {
|
||||||
updatePosition(obj)
|
updatePosition(vision)
|
||||||
//layers.enable(obj.layer)
|
//layers.enable(obj.layer)
|
||||||
//add listener to object properties
|
//add listener to object properties
|
||||||
obj.onPropertyChange { propertyName ->
|
if(observe) {
|
||||||
updateProperty(obj, propertyName)
|
vision.onPropertyChange(three.context) { propertyName ->
|
||||||
|
updateProperty(vision, propertyName)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -49,7 +49,7 @@ public object ThreeMaterials {
|
|||||||
cached = true
|
cached = true
|
||||||
}
|
}
|
||||||
|
|
||||||
private val lineMaterialCache = HashMap<Meta, LineBasicMaterial>()
|
private val lineMaterialCache = HashMap<Int, LineBasicMaterial>()
|
||||||
|
|
||||||
private fun buildLineMaterial(meta: Meta): LineBasicMaterial = LineBasicMaterial().apply {
|
private fun buildLineMaterial(meta: Meta): LineBasicMaterial = LineBasicMaterial().apply {
|
||||||
color = meta[SolidMaterial.COLOR_KEY]?.threeColor() ?: DEFAULT_LINE_COLOR
|
color = meta[SolidMaterial.COLOR_KEY]?.threeColor() ?: DEFAULT_LINE_COLOR
|
||||||
@ -61,14 +61,12 @@ public object ThreeMaterials {
|
|||||||
public fun getLineMaterial(meta: Meta?, cache: Boolean): LineBasicMaterial {
|
public fun getLineMaterial(meta: Meta?, cache: Boolean): LineBasicMaterial {
|
||||||
if (meta == null) return DEFAULT_LINE
|
if (meta == null) return DEFAULT_LINE
|
||||||
return if (cache) {
|
return if (cache) {
|
||||||
lineMaterialCache.getOrPut(meta) { buildLineMaterial(meta) }
|
lineMaterialCache.getOrPut(meta.hashCode()) { buildLineMaterial(meta) }
|
||||||
} else {
|
} else {
|
||||||
buildLineMaterial(meta)
|
buildLineMaterial(meta)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private val materialCache = HashMap<Meta, Material>()
|
|
||||||
|
|
||||||
internal fun buildMaterial(meta: Meta): Material = when (meta[SolidMaterial.TYPE_KEY]?.string) {
|
internal fun buildMaterial(meta: Meta): Material = when (meta[SolidMaterial.TYPE_KEY]?.string) {
|
||||||
"simple" -> MeshBasicMaterial().apply {
|
"simple" -> MeshBasicMaterial().apply {
|
||||||
color = meta[SolidMaterial.COLOR_KEY]?.threeColor() ?: DEFAULT_COLOR
|
color = meta[SolidMaterial.COLOR_KEY]?.threeColor() ?: DEFAULT_COLOR
|
||||||
@ -85,7 +83,9 @@ public object ThreeMaterials {
|
|||||||
needsUpdate = true
|
needsUpdate = true
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun cacheMaterial(meta: Meta): Material = materialCache.getOrPut(meta) {
|
private val materialCache = HashMap<Int, Material>()
|
||||||
|
|
||||||
|
internal fun cacheMaterial(meta: Meta): Material = materialCache.getOrPut(meta.hashCode()) {
|
||||||
buildMaterial(meta).apply {
|
buildMaterial(meta).apply {
|
||||||
cached = true
|
cached = true
|
||||||
}
|
}
|
||||||
@ -130,11 +130,11 @@ private var Material.cached: Boolean
|
|||||||
userData["cached"] = value
|
userData["cached"] = value
|
||||||
}
|
}
|
||||||
|
|
||||||
public fun Mesh.updateMaterial(vision: Vision) {
|
public fun Mesh.createMaterial(vision: Vision) {
|
||||||
val ownMaterialMeta = vision.properties.own?.get(SolidMaterial.MATERIAL_KEY)
|
val ownMaterialMeta = vision.properties.own?.get(SolidMaterial.MATERIAL_KEY)
|
||||||
if (ownMaterialMeta == null) {
|
if (ownMaterialMeta == null) {
|
||||||
if (vision is SolidReference && vision.getStyleNodes(SolidMaterial.MATERIAL_KEY).isEmpty()) {
|
if (vision is SolidReference && vision.getStyleNodes(SolidMaterial.MATERIAL_KEY).isEmpty()) {
|
||||||
updateMaterial(vision.prototype)
|
createMaterial(vision.prototype)
|
||||||
} else {
|
} else {
|
||||||
material = ThreeMaterials.cacheMaterial(vision.properties.getProperty(SolidMaterial.MATERIAL_KEY))
|
material = ThreeMaterials.cacheMaterial(vision.properties.getProperty(SolidMaterial.MATERIAL_KEY))
|
||||||
}
|
}
|
||||||
@ -150,7 +150,7 @@ public fun Mesh.updateMaterialProperty(vision: Vision, propertyName: Name) {
|
|||||||
|| propertyName == SolidMaterial.MATERIAL_KEY + SolidMaterial.TYPE_KEY
|
|| propertyName == SolidMaterial.MATERIAL_KEY + SolidMaterial.TYPE_KEY
|
||||||
) {
|
) {
|
||||||
//generate a new material since cached material should not be changed
|
//generate a new material since cached material should not be changed
|
||||||
updateMaterial(vision)
|
createMaterial(vision)
|
||||||
} else {
|
} else {
|
||||||
when (propertyName) {
|
when (propertyName) {
|
||||||
SolidMaterial.MATERIAL_COLOR_KEY -> {
|
SolidMaterial.MATERIAL_COLOR_KEY -> {
|
||||||
|
@ -30,32 +30,34 @@ public abstract class ThreeMeshFactory<in T : Solid>(
|
|||||||
*/
|
*/
|
||||||
public abstract fun buildGeometry(obj: T): BufferGeometry
|
public abstract fun buildGeometry(obj: T): BufferGeometry
|
||||||
|
|
||||||
override fun build(three: ThreePlugin, obj: T): Mesh {
|
override fun build(three: ThreePlugin, vision: T, observe: Boolean): Mesh {
|
||||||
val geometry = buildGeometry(obj)
|
val geometry = buildGeometry(vision)
|
||||||
|
|
||||||
//val meshMeta: Meta = obj.properties[Material3D.MATERIAL_KEY]?.node ?: Meta.empty
|
//val meshMeta: Meta = obj.properties[Material3D.MATERIAL_KEY]?.node ?: Meta.empty
|
||||||
|
|
||||||
val mesh = Mesh(geometry, ThreeMaterials.DEFAULT).apply {
|
val mesh = Mesh(geometry, ThreeMaterials.DEFAULT).apply {
|
||||||
matrixAutoUpdate = false
|
matrixAutoUpdate = false
|
||||||
//set position for mesh
|
//set position for mesh
|
||||||
updatePosition(obj)
|
updatePosition(vision)
|
||||||
applyProperties(obj)
|
applyProperties(vision)
|
||||||
}
|
}
|
||||||
|
|
||||||
//add listener to object properties
|
if(observe) {
|
||||||
obj.onPropertyChange { name->
|
//add listener to object properties
|
||||||
when {
|
vision.onPropertyChange(three.context) { name ->
|
||||||
name.startsWith(Solid.GEOMETRY_KEY) -> {
|
when {
|
||||||
val oldGeometry = mesh.geometry
|
name.startsWith(Solid.GEOMETRY_KEY) -> {
|
||||||
val newGeometry = buildGeometry(obj)
|
val oldGeometry = mesh.geometry
|
||||||
oldGeometry.attributes = newGeometry.attributes
|
val newGeometry = buildGeometry(vision)
|
||||||
//mesh.applyWireFrame(obj)
|
oldGeometry.attributes = newGeometry.attributes
|
||||||
mesh.applyEdges(obj)
|
//mesh.applyWireFrame(obj)
|
||||||
newGeometry.dispose()
|
mesh.applyEdges(vision)
|
||||||
|
newGeometry.dispose()
|
||||||
|
}
|
||||||
|
//name.startsWith(WIREFRAME_KEY) -> mesh.applyWireFrame(obj)
|
||||||
|
name.startsWith(EDGES_KEY) -> mesh.applyEdges(vision)
|
||||||
|
else -> mesh.updateProperty(vision, name)
|
||||||
}
|
}
|
||||||
//name.startsWith(WIREFRAME_KEY) -> mesh.applyWireFrame(obj)
|
|
||||||
name.startsWith(EDGES_KEY) -> mesh.applyEdges(obj)
|
|
||||||
else -> mesh.updateProperty(obj, name)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -76,26 +78,26 @@ public abstract class ThreeMeshFactory<in T : Solid>(
|
|||||||
|
|
||||||
@VisionBuilder
|
@VisionBuilder
|
||||||
public fun Solid.edges(enabled: Boolean = true, block: SolidMaterial.() -> Unit = {}) {
|
public fun Solid.edges(enabled: Boolean = true, block: SolidMaterial.() -> Unit = {}) {
|
||||||
properties.set(EDGES_ENABLED_KEY, enabled)
|
properties[EDGES_ENABLED_KEY] = enabled
|
||||||
SolidMaterial.write(properties.getProperty(EDGES_MATERIAL_KEY)).apply(block)
|
SolidMaterial.write(properties.getProperty(EDGES_MATERIAL_KEY)).apply(block)
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun Mesh.applyProperties(obj: Solid): Mesh = apply {
|
internal fun Mesh.applyProperties(vision: Solid): Mesh = apply {
|
||||||
updateMaterial(obj)
|
createMaterial(vision)
|
||||||
applyEdges(obj)
|
applyEdges(vision)
|
||||||
//applyWireFrame(obj)
|
//applyWireFrame(obj)
|
||||||
layers.set(obj.layer)
|
layers.set(vision.layer)
|
||||||
children.forEach {
|
children.forEach {
|
||||||
it.layers.set(obj.layer)
|
it.layers.set(vision.layer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public fun Mesh.applyEdges(obj: Solid) {
|
public fun Mesh.applyEdges(vision: Solid) {
|
||||||
val edges = children.find { it.name == "@edges" } as? LineSegments
|
val edges = children.find { it.name == "@edges" } as? LineSegments
|
||||||
//inherited edges definition, enabled by default
|
//inherited edges definition, enabled by default
|
||||||
if (obj.properties.getProperty(EDGES_ENABLED_KEY, inherit = true).boolean != false) {
|
if (vision.properties.getValue(EDGES_ENABLED_KEY, inherit = true)?.boolean != false) {
|
||||||
val bufferGeometry = geometry as? BufferGeometry ?: return
|
val bufferGeometry = geometry as? BufferGeometry ?: return
|
||||||
val material = ThreeMaterials.getLineMaterial(obj.properties.getProperty(EDGES_MATERIAL_KEY), true)
|
val material = ThreeMaterials.getLineMaterial(vision.properties.getProperty(EDGES_MATERIAL_KEY), true)
|
||||||
if (edges == null) {
|
if (edges == null) {
|
||||||
add(
|
add(
|
||||||
LineSegments(
|
LineSegments(
|
||||||
|
@ -11,7 +11,7 @@ import space.kscience.dataforge.meta.update
|
|||||||
import space.kscience.dataforge.names.*
|
import space.kscience.dataforge.names.*
|
||||||
import space.kscience.visionforge.ElementVisionRenderer
|
import space.kscience.visionforge.ElementVisionRenderer
|
||||||
import space.kscience.visionforge.Vision
|
import space.kscience.visionforge.Vision
|
||||||
import space.kscience.visionforge.onPropertyChange
|
import space.kscience.visionforge.VisionChildren
|
||||||
import space.kscience.visionforge.solid.*
|
import space.kscience.visionforge.solid.*
|
||||||
import space.kscience.visionforge.solid.specifications.Canvas3DOptions
|
import space.kscience.visionforge.solid.specifications.Canvas3DOptions
|
||||||
import space.kscience.visionforge.visible
|
import space.kscience.visionforge.visible
|
||||||
@ -48,69 +48,75 @@ public class ThreePlugin : AbstractPlugin(), ElementVisionRenderer {
|
|||||||
as ThreeFactory<Solid>?
|
as ThreeFactory<Solid>?
|
||||||
}
|
}
|
||||||
|
|
||||||
public fun buildObject3D(obj: Solid): Object3D = when (obj) {
|
public fun buildObject3D(vision: Solid, observe: Boolean = true): Object3D = when (vision) {
|
||||||
is ThreeJsVision -> obj.render(this)
|
is ThreeJsVision -> vision.render(this)
|
||||||
is SolidReference -> ThreeReferenceFactory.build(this, obj)
|
is SolidReference -> ThreeReferenceFactory.build(this, vision, observe)
|
||||||
is SolidGroup -> {
|
is SolidGroup -> {
|
||||||
val group = ThreeGroup()
|
val group = ThreeGroup()
|
||||||
obj.items.forEach { (token, child) ->
|
vision.items.forEach { (token, child) ->
|
||||||
if (token != SolidGroup.PROTOTYPES_TOKEN && child.ignore != true) {
|
if (token != SolidGroup.PROTOTYPES_TOKEN && child.ignore != true) {
|
||||||
try {
|
try {
|
||||||
val object3D = buildObject3D(child)
|
val object3D = buildObject3D(
|
||||||
|
child,
|
||||||
|
if (token.body == VisionChildren.STATIC_TOKEN_BODY) false else observe
|
||||||
|
)
|
||||||
|
// disable tracking changes for statics
|
||||||
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()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
group.apply {
|
group.apply {
|
||||||
updatePosition(obj)
|
updatePosition(vision)
|
||||||
//obj.onChildrenChange()
|
//obj.onChildrenChange()
|
||||||
|
if (observe) {
|
||||||
obj.onPropertyChange(context) { name ->
|
vision.properties.changes.onEach { name ->
|
||||||
if (
|
if (
|
||||||
name.startsWith(Solid.POSITION_KEY) ||
|
name.startsWith(Solid.POSITION_KEY) ||
|
||||||
name.startsWith(Solid.ROTATION_KEY) ||
|
name.startsWith(Solid.ROTATION_KEY) ||
|
||||||
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(vision)
|
||||||
} else if (name == Vision.VISIBLE_KEY) {
|
} else if (name == Vision.VISIBLE_KEY) {
|
||||||
visible = obj.visible ?: true
|
visible = vision.visible ?: true
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
obj.children.changes.onEach { childName ->
|
|
||||||
val child = obj.children.getChild(childName)
|
|
||||||
|
|
||||||
//removing old object
|
|
||||||
findChild(childName)?.let { oldChild ->
|
|
||||||
oldChild.parent?.remove(oldChild)
|
|
||||||
}
|
|
||||||
|
|
||||||
//adding new object
|
|
||||||
if (child != null && child is Solid) {
|
|
||||||
try {
|
|
||||||
val object3D = buildObject3D(child)
|
|
||||||
set(childName, object3D)
|
|
||||||
} catch (ex: Throwable) {
|
|
||||||
logger.error(ex) { "Failed to render $child" }
|
|
||||||
}
|
}
|
||||||
}
|
}.launchIn(context)
|
||||||
}.launchIn(context)
|
|
||||||
|
vision.children.changes.onEach { childName ->
|
||||||
|
if(childName.isEmpty()) return@onEach
|
||||||
|
|
||||||
|
val child = vision.children.getChild(childName)
|
||||||
|
|
||||||
|
//removing old object
|
||||||
|
findChild(childName)?.let { oldChild ->
|
||||||
|
oldChild.parent?.remove(oldChild)
|
||||||
|
}
|
||||||
|
|
||||||
|
//adding new object
|
||||||
|
if (child != null && child is Solid) {
|
||||||
|
try {
|
||||||
|
val object3D = buildObject3D(child)
|
||||||
|
set(childName, object3D)
|
||||||
|
} catch (ex: Throwable) {
|
||||||
|
logger.error(ex) { "Failed to render $child" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.launchIn(context)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
is Composite -> compositeFactory.build(this, obj)
|
is Composite -> compositeFactory.build(this, vision, observe)
|
||||||
else -> {
|
else -> {
|
||||||
//find specialized factory for this type if it is present
|
//find specialized factory for this type if it is present
|
||||||
val factory: ThreeFactory<Solid>? = findObjectFactory(obj::class)
|
val factory: ThreeFactory<Solid>? = findObjectFactory(vision::class)
|
||||||
when {
|
when {
|
||||||
factory != null -> factory.build(this, obj)
|
factory != null -> factory.build(this, vision, observe)
|
||||||
obj is GeometrySolid -> ThreeShapeFactory.build(this, obj)
|
vision is GeometrySolid -> ThreeShapeFactory.build(this, vision, observe)
|
||||||
else -> error("Renderer for ${obj::class} not found")
|
else -> error("Renderer for ${vision::class} not found")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,19 +13,21 @@ public object ThreePointLightFactory : ThreeFactory<PointLightSource> {
|
|||||||
|
|
||||||
private val DEFAULT_COLOR = Color(0x404040)
|
private val DEFAULT_COLOR = Color(0x404040)
|
||||||
|
|
||||||
override fun build(three: ThreePlugin, obj: PointLightSource): PointLight {
|
override fun build(three: ThreePlugin, vision: PointLightSource, observe: Boolean): PointLight {
|
||||||
val res = PointLight().apply {
|
val res = PointLight().apply {
|
||||||
matrixAutoUpdate = false
|
matrixAutoUpdate = false
|
||||||
color = obj.color.threeColor() ?: DEFAULT_COLOR
|
color = vision.color.threeColor() ?: DEFAULT_COLOR
|
||||||
intensity = obj.intensity.toDouble()
|
intensity = vision.intensity.toDouble()
|
||||||
updatePosition(obj)
|
updatePosition(vision)
|
||||||
}
|
}
|
||||||
|
|
||||||
obj.onPropertyChange { name ->
|
if(observe) {
|
||||||
when (name) {
|
vision.onPropertyChange(three.context) { name ->
|
||||||
LightSource::color.name.asName() -> res.color = obj.color.threeColor() ?: DEFAULT_COLOR
|
when (name) {
|
||||||
LightSource::intensity.name.asName() -> res.intensity = obj.intensity.toDouble()
|
LightSource::color.name.asName() -> res.color = vision.color.threeColor() ?: DEFAULT_COLOR
|
||||||
else -> res.updateProperty(obj, name)
|
LightSource::intensity.name.asName() -> res.intensity = vision.intensity.toDouble()
|
||||||
|
else -> res.updateProperty(vision, name)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,33 +31,35 @@ public object ThreeReferenceFactory : ThreeFactory<SolidReference> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun build(three: ThreePlugin, obj: SolidReference): Object3D {
|
override fun build(three: ThreePlugin, vision: SolidReference, observe: Boolean): Object3D {
|
||||||
val template = obj.prototype
|
val template = vision.prototype
|
||||||
val cachedObject = cache.getOrPut(template) {
|
val cachedObject = cache.getOrPut(template) {
|
||||||
three.buildObject3D(template)
|
three.buildObject3D(template)
|
||||||
}
|
}
|
||||||
|
|
||||||
val object3D: Object3D = cachedObject.replicate()
|
val object3D: Object3D = cachedObject.replicate()
|
||||||
object3D.updatePosition(obj)
|
object3D.updatePosition(vision)
|
||||||
|
|
||||||
if (object3D is Mesh) {
|
if (object3D is Mesh) {
|
||||||
//object3D.material = ThreeMaterials.buildMaterial(obj.getProperty(SolidMaterial.MATERIAL_KEY).node!!)
|
//object3D.material = ThreeMaterials.buildMaterial(obj.getProperty(SolidMaterial.MATERIAL_KEY).node!!)
|
||||||
object3D.applyProperties(obj)
|
object3D.applyProperties(vision)
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO apply child properties
|
//TODO apply child properties
|
||||||
|
|
||||||
obj.onPropertyChange { name ->
|
if (observe) {
|
||||||
if (name.firstOrNull()?.body == REFERENCE_CHILD_PROPERTY_PREFIX) {
|
vision.onPropertyChange(three.context) { name ->
|
||||||
val childName = name.firstOrNull()?.index?.let(Name::parse)
|
if (name.firstOrNull()?.body == REFERENCE_CHILD_PROPERTY_PREFIX) {
|
||||||
?: error("Wrong syntax for reference child property: '$name'")
|
val childName = name.firstOrNull()?.index?.let(Name::parse)
|
||||||
val propertyName = name.cutFirst()
|
?: error("Wrong syntax for reference child property: '$name'")
|
||||||
val referenceChild =
|
val propertyName = name.cutFirst()
|
||||||
obj.children.getChild(childName) ?: error("Reference child with name '$childName' not found")
|
val referenceChild =
|
||||||
val child = object3D.findChild(childName) ?: error("Object child with name '$childName' not found")
|
vision.children.getChild(childName) ?: error("Reference child with name '$childName' not found")
|
||||||
child.updateProperty(referenceChild, propertyName)
|
val child = object3D.findChild(childName) ?: error("Object child with name '$childName' not found")
|
||||||
} else {
|
child.updateProperty(referenceChild, propertyName)
|
||||||
object3D.updateProperty(obj, name)
|
} else {
|
||||||
|
object3D.updateProperty(vision, name)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
plugins {
|
plugins {
|
||||||
id("space.kscience.gradle.mpp")
|
id("space.kscience.gradle.mpp")
|
||||||
}
|
}
|
||||||
|
|
||||||
val ktorVersion: String by rootProject.extra
|
val ktorVersion: String by rootProject.extra
|
||||||
|
|
||||||
kotlin {
|
kotlin {
|
||||||
js(IR){
|
js(IR) {
|
||||||
browser {
|
browser {
|
||||||
webpackTask {
|
webpackTask {
|
||||||
this.outputFileName = "js/visionforge-three.js"
|
this.outputFileName = "js/visionforge-three.js"
|
||||||
@ -14,17 +14,6 @@ kotlin {
|
|||||||
binaries.executable()
|
binaries.executable()
|
||||||
}
|
}
|
||||||
|
|
||||||
afterEvaluate {
|
|
||||||
val jsBrowserDistribution by tasks.getting
|
|
||||||
|
|
||||||
tasks.getByName<ProcessResources>("jvmProcessResources") {
|
|
||||||
dependsOn(jsBrowserDistribution)
|
|
||||||
afterEvaluate {
|
|
||||||
from(jsBrowserDistribution)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sourceSets {
|
sourceSets {
|
||||||
commonMain {
|
commonMain {
|
||||||
dependencies {
|
dependencies {
|
||||||
@ -43,3 +32,21 @@ kotlin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
val jsBrowserDistribution by tasks.getting
|
||||||
|
val jsBrowserDevelopmentExecutableDistribution by tasks.getting
|
||||||
|
|
||||||
|
val devMode = rootProject.findProperty("visionforge.development") as? Boolean
|
||||||
|
?: rootProject.version.toString().contains("dev")
|
||||||
|
|
||||||
|
tasks.getByName<ProcessResources>("jvmProcessResources") {
|
||||||
|
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
|
||||||
|
if (devMode) {
|
||||||
|
dependsOn(jsBrowserDevelopmentExecutableDistribution)
|
||||||
|
from(jsBrowserDevelopmentExecutableDistribution)
|
||||||
|
} else {
|
||||||
|
dependsOn(jsBrowserDistribution)
|
||||||
|
from(jsBrowserDistribution)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user