Fix reference rendering
This commit is contained in:
@ -9,9 +9,11 @@ import space.kscience.visionforge.Colors
|
||||
import space.kscience.visionforge.gdml.toVision
|
||||
import space.kscience.visionforge.html.VisionForgeStyles
|
||||
import space.kscience.visionforge.html.startApplication
|
||||
import space.kscience.visionforge.setAsRoot
|
||||
import space.kscience.visionforge.solid.ambientLight
|
||||
import space.kscience.visionforge.solid.invoke
|
||||
import space.kscience.visionforge.solid.three.ThreePlugin
|
||||
import space.kscience.visionforge.visionManager
|
||||
|
||||
|
||||
fun main() = startApplication { document ->
|
||||
@ -26,6 +28,7 @@ fun main() = startApplication { document ->
|
||||
ambientLight {
|
||||
color(Colors.white)
|
||||
}
|
||||
setAsRoot(context.visionManager)
|
||||
}
|
||||
|
||||
renderComposable(element) {
|
||||
|
@ -78,7 +78,7 @@ internal class VisionPropertyTest {
|
||||
var callCounter = 0
|
||||
|
||||
val subscription = child.useProperty("test", inherited = true) {
|
||||
deferred.complete(it.value)
|
||||
deferred.complete(it?.value)
|
||||
callCounter++
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,34 @@
|
||||
package space.kscience.visionforge.gdml
|
||||
|
||||
import org.junit.jupiter.api.fail
|
||||
import space.kscience.dataforge.context.Global
|
||||
import space.kscience.dataforge.names.Name
|
||||
import space.kscience.dataforge.names.plus
|
||||
import space.kscience.gdml.Gdml
|
||||
import space.kscience.gdml.decodeFromStream
|
||||
import space.kscience.visionforge.Vision
|
||||
import space.kscience.visionforge.VisionGroup
|
||||
import space.kscience.visionforge.setAsRoot
|
||||
import space.kscience.visionforge.visionManager
|
||||
import kotlin.test.Test
|
||||
|
||||
class TestConsistency {
|
||||
|
||||
private fun failOnOrphan(vision: Vision, prefix: Name = Name.EMPTY) {
|
||||
if(vision.parent == null) fail { "Parent is not defined for $vision with name '$prefix'" }
|
||||
if(vision is VisionGroup<*>){
|
||||
vision.visions.forEach { (token, child)->
|
||||
failOnOrphan(child, prefix + token)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public fun noOrphans() {
|
||||
val stream = javaClass.getResourceAsStream("/gdml/cubes.gdml")!!
|
||||
val gdml = Gdml.decodeFromStream(stream)
|
||||
val vision = gdml.toVision()
|
||||
vision.setAsRoot(Global.visionManager)
|
||||
failOnOrphan(vision)
|
||||
}
|
||||
}
|
@ -63,7 +63,7 @@ public class SolidGroup : AbstractVision(), SolidContainer, PrototypeHolder, Mut
|
||||
* If a prototype is a ref, then it is unfolded automatically.
|
||||
*/
|
||||
override fun getPrototype(name: Name): Solid? =
|
||||
prototypes?.getVision(name)?.prototype ?: (parent as? PrototypeHolder)?.getPrototype(name)
|
||||
prototypes?.getVision(name) ?: (parent as? PrototypeHolder)?.getPrototype(name)
|
||||
|
||||
/**
|
||||
* Create or edit prototype node as a group
|
||||
|
@ -27,8 +27,8 @@ import space.kscience.visionforge.solid.SolidReference.Companion.REFERENCE_CHILD
|
||||
@Suppress("RecursivePropertyAccessor")
|
||||
public val Vision.prototype: Solid
|
||||
get() = when (this) {
|
||||
is SolidReference -> prototype.prototype
|
||||
is SolidReferenceChild -> prototype.prototype
|
||||
is SolidReference -> prototype
|
||||
is SolidReferenceChild -> prototype
|
||||
is Solid -> this
|
||||
else -> error("This Vision is neither Solid nor SolidReference")
|
||||
}
|
||||
@ -75,7 +75,9 @@ public class SolidReference(
|
||||
} ?: emptyMap()
|
||||
|
||||
|
||||
override fun getVision(token: NameToken): Solid? = (prototype as? SolidContainer)?.getVision(token)
|
||||
override fun getVision(token: NameToken): Solid? = (prototype as? SolidContainer)?.getVision(token)?.let {
|
||||
SolidReferenceChild(this@SolidReference, it, token.asName())
|
||||
}
|
||||
|
||||
|
||||
override fun readProperty(
|
||||
@ -208,6 +210,7 @@ private class SolidReferenceChild(
|
||||
inherited: Boolean,
|
||||
useStyles: Boolean
|
||||
): Meta? {
|
||||
println("read reference property")
|
||||
val listOfMeta = buildList {
|
||||
//1. resolve own properties
|
||||
add(properties[name])
|
||||
@ -239,6 +242,10 @@ private class SolidReferenceChild(
|
||||
SolidReferenceChild(owner, this, childName + key)
|
||||
} ?: emptyMap()
|
||||
|
||||
override fun getVision(token: NameToken): Solid? = (prototype as? SolidContainer)?.getVision(token)?.let {
|
||||
SolidReferenceChild(owner, it, childName + token)
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
private fun childToken(childName: Name): NameToken =
|
||||
|
@ -1,12 +1,15 @@
|
||||
package space.kscience.visionforge.solid
|
||||
|
||||
import kotlinx.serialization.json.encodeToJsonElement
|
||||
import space.kscience.dataforge.meta.string
|
||||
import space.kscience.dataforge.misc.DFExperimental
|
||||
import space.kscience.dataforge.names.get
|
||||
import space.kscience.dataforge.names.parseAsName
|
||||
import space.kscience.visionforge.style
|
||||
import space.kscience.visionforge.useStyle
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
@DFExperimental
|
||||
class SolidReferenceTest {
|
||||
@ -14,23 +17,59 @@ class SolidReferenceTest {
|
||||
val theStyle by style {
|
||||
SolidMaterial.MATERIAL_COLOR_KEY put "red"
|
||||
}
|
||||
newRef("test", Box(100f,100f,100f).apply {
|
||||
newRef("test", Box(100f, 100f, 100f).apply {
|
||||
color("blue")
|
||||
useStyle(theStyle)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
fun testReferenceProperty(){
|
||||
fun testReferenceProperty() {
|
||||
assertEquals("blue", (groupWithReference.get("test") as Solid).color.string)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testReferenceSerialization(){
|
||||
fun testReferenceSerialization() {
|
||||
val serialized = Solids.jsonForSolids.encodeToJsonElement(groupWithReference)
|
||||
val deserialized = Solids.jsonForSolids.decodeFromJsonElement(SolidGroup.serializer(), serialized)
|
||||
assertEquals(groupWithReference.visions["test"]?.color?.string, deserialized.visions["test"]?.color?.string)
|
||||
assertEquals("blue", (deserialized["test"] as Solid).color.string)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun refRef() {
|
||||
val group = testSolids.solidGroup {
|
||||
prototypes {
|
||||
solidGroup("group") {
|
||||
box(100, 100, 100, "refGroupChild")
|
||||
}
|
||||
ref("group.refGroupChild".parseAsName(), "refRef")
|
||||
}
|
||||
ref("refRef".parseAsName(), "refRefRef")
|
||||
ref("group".parseAsName(), "groupRef")
|
||||
}
|
||||
|
||||
val boxRef = group["refRefRef"]!!
|
||||
|
||||
boxRef.color("red")
|
||||
|
||||
assertTrue { boxRef.prototype is SolidReference }
|
||||
|
||||
assertTrue { boxRef.prototype.prototype is Box }
|
||||
|
||||
assertEquals("red", boxRef.properties[SolidMaterial.MATERIAL_COLOR_KEY].string)
|
||||
assertEquals(null, boxRef.prototype.properties[SolidMaterial.MATERIAL_COLOR_KEY])
|
||||
assertEquals(null, boxRef.prototype.prototype.properties[SolidMaterial.MATERIAL_COLOR_KEY])
|
||||
|
||||
val groupRef = group["groupRef"] as SolidContainer
|
||||
val groupChildRef = groupRef.getVision("refGroupChild")
|
||||
|
||||
assertTrue(groupChildRef?.prototype is Box)
|
||||
|
||||
groupChildRef.color("blue")
|
||||
|
||||
assertEquals("blue", groupChildRef.properties[SolidMaterial.MATERIAL_COLOR_KEY].string)
|
||||
assertEquals(null, boxRef.prototype.properties[SolidMaterial.MATERIAL_COLOR_KEY])
|
||||
assertEquals(null, boxRef.prototype.prototype.properties[SolidMaterial.MATERIAL_COLOR_KEY])
|
||||
}
|
||||
}
|
@ -23,8 +23,8 @@ kscience {
|
||||
api("io.github.vinceglb:filekit-core:0.8.8")
|
||||
// api(npm("file-saver", "2.0.5"))
|
||||
// api(npm("@types/file-saver", "2.0.7"))
|
||||
implementation(npm("three", "0.143.0"))
|
||||
implementation(npm("three-csg-ts", "3.1.13"))
|
||||
implementation(npm("three", "0.173.0"))
|
||||
implementation(npm("three-csg-ts", "3.2.0"))
|
||||
implementation(npm("three.meshline", "1.4.0"))
|
||||
}
|
||||
}
|
||||
|
@ -65,7 +65,7 @@ public fun Object3D.updatePosition(vision: Vision) {
|
||||
* Update non-position non-geometry property
|
||||
*/
|
||||
public fun Object3D.updateProperty(source: Solid, propertyName: Name) {
|
||||
//console.log("${source::class} updated $propertyName with ${source.readProperty(propertyName, inherited = true)}")
|
||||
// console.log("${source::class} updated $propertyName with ${source.readProperty(propertyName, inherited = true)}")
|
||||
if (isMesh(this) && propertyName.startsWith(MATERIAL_KEY)) {
|
||||
updateMaterialProperty(source, propertyName)
|
||||
} else if (
|
||||
|
@ -6,6 +6,7 @@ import space.kscience.dataforge.names.asName
|
||||
import space.kscience.dataforge.names.plus
|
||||
import space.kscience.visionforge.Colors
|
||||
import space.kscience.visionforge.Vision
|
||||
import space.kscience.visionforge.getStyleNodes
|
||||
import space.kscience.visionforge.solid.ColorAccessor
|
||||
import space.kscience.visionforge.solid.SolidMaterial
|
||||
import space.kscience.visionforge.solid.SolidReference
|
||||
@ -132,8 +133,8 @@ internal var Material.cached: Boolean
|
||||
|
||||
public fun Mesh.setMaterial(vision: Vision) {
|
||||
if (
|
||||
vision.readProperty(SolidMaterial.MATERIAL_KEY) == null
|
||||
// && vision.getStyleNodes(SolidMaterial.MATERIAL_KEY).isEmpty()
|
||||
vision.properties[SolidMaterial.MATERIAL_KEY] == null
|
||||
&& vision.getStyleNodes(SolidMaterial.MATERIAL_KEY).isEmpty()
|
||||
) {
|
||||
//if this is a reference, use material of the prototype
|
||||
if (vision is SolidReference) {
|
||||
@ -141,7 +142,7 @@ public fun Mesh.setMaterial(vision: Vision) {
|
||||
} else {
|
||||
material = vision.parent?.let { parent ->
|
||||
//TODO cache parent material
|
||||
ThreeMaterials.buildMaterial(parent.properties[SolidMaterial.MATERIAL_KEY] ?: Meta.EMPTY)
|
||||
ThreeMaterials.buildMaterial(parent.readProperty(SolidMaterial.MATERIAL_KEY) ?: Meta.EMPTY)
|
||||
} ?: ThreeMaterials.cacheMaterial(vision)
|
||||
}
|
||||
} else {
|
||||
@ -168,8 +169,7 @@ public fun Mesh.updateMaterialProperty(vision: Vision, propertyName: Name) {
|
||||
|
||||
SolidMaterial.SPECULAR_COLOR_KEY -> {
|
||||
material.asDynamic().specular =
|
||||
vision.readProperty(SolidMaterial.SPECULAR_COLOR_KEY)
|
||||
?.threeColor()
|
||||
vision.readProperty(SolidMaterial.SPECULAR_COLOR_KEY)?.threeColor()
|
||||
?: ThreeMaterials.DEFAULT_COLOR
|
||||
}
|
||||
|
||||
@ -192,11 +192,12 @@ public fun Mesh.updateMaterialProperty(vision: Vision, propertyName: Name) {
|
||||
material.asDynamic().wireframe = vision.readProperty(
|
||||
SolidMaterial.MATERIAL_WIREFRAME_KEY,
|
||||
inherited = true,
|
||||
)?.boolean ?: false
|
||||
)?.boolean == true
|
||||
}
|
||||
|
||||
else -> console.warn("Unrecognized material property: $propertyName")
|
||||
}
|
||||
|
||||
material.needsUpdate = true
|
||||
}
|
||||
}
|
@ -37,6 +37,7 @@ public class ThreePlugin : AbstractPlugin(), ComposeHtmlVisionRenderer {
|
||||
|
||||
init {
|
||||
//Add specialized factories here
|
||||
objectFactories[SolidReference::class] = ThreeReferenceFactory
|
||||
objectFactories[Box::class] = ThreeBoxFactory
|
||||
objectFactories[Convex::class] = ThreeConvexFactory
|
||||
objectFactories[Sphere::class] = ThreeSphereFactory
|
||||
@ -63,7 +64,6 @@ public class ThreePlugin : AbstractPlugin(), ComposeHtmlVisionRenderer {
|
||||
*/
|
||||
public suspend fun buildObject3D(vision: Solid, observe: Boolean = true): Object3D = when (vision) {
|
||||
is ThreeJsVision -> vision.render(this)
|
||||
is SolidReference -> ThreeReferenceFactory.build(this, vision, observe)
|
||||
is SolidGroup -> {
|
||||
val group = ThreeGroup()
|
||||
vision.visions.forEach { (name, child) ->
|
||||
|
@ -12,37 +12,48 @@ import three.core.Object3D
|
||||
import three.objects.Mesh
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
private fun Object3D.lockMaterial(){
|
||||
if(this is Mesh){
|
||||
material.cached = true
|
||||
}
|
||||
children.forEach {
|
||||
it.lockMaterial()
|
||||
}
|
||||
}
|
||||
|
||||
public object ThreeReferenceFactory : ThreeFactory<SolidReference> {
|
||||
private val cache = HashMap<Solid, Object3D>()
|
||||
|
||||
override val type: KClass<SolidReference> = SolidReference::class
|
||||
|
||||
private fun Object3D.replicate(): Object3D = when {
|
||||
isMesh(this) -> Mesh(geometry, material).also {
|
||||
//clone geometry
|
||||
it.material.cached = true
|
||||
it.applyMatrix4(matrix)
|
||||
}
|
||||
// private fun Object3D.replicate(): Object3D = when {
|
||||
// isMesh(this) -> Mesh(geometry, material).also {
|
||||
// //clone geometry
|
||||
// it.material.cached = true
|
||||
// it.applyMatrix4(matrix)
|
||||
// }
|
||||
//
|
||||
// else -> clone(false)
|
||||
// }.also { obj: Object3D ->
|
||||
// obj.name = this.name
|
||||
// children.forEach { child: Object3D ->
|
||||
// obj.add(child.replicate())
|
||||
// }
|
||||
// }
|
||||
|
||||
else -> clone(false)
|
||||
}.also { obj: Object3D ->
|
||||
obj.name = this.name
|
||||
children.forEach { child: Object3D ->
|
||||
obj.add(child.replicate())
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun build(three: ThreePlugin, vision: SolidReference, observe: Boolean): Object3D {
|
||||
val template = vision.prototype
|
||||
val cachedObject = cache.getOrPut(template) {
|
||||
three.buildObject3D(template)
|
||||
three.buildObject3D(template).apply {
|
||||
lockMaterial()
|
||||
}
|
||||
}
|
||||
|
||||
val object3D: Object3D = cachedObject.replicate()
|
||||
val object3D: Object3D = cachedObject.clone(true)
|
||||
object3D.updatePosition(vision)
|
||||
|
||||
if (isMesh(object3D)) {
|
||||
//object3D.material = ThreeMaterials.buildMaterial(obj.getProperty(SolidMaterial.MATERIAL_KEY).node!!)
|
||||
object3D.applyProperties(vision)
|
||||
}
|
||||
|
||||
|
@ -23,6 +23,7 @@ import space.kscience.visionforge.solid.specifications.Canvas3DOptions
|
||||
import space.kscience.visionforge.solid.three.ThreeCanvas
|
||||
import space.kscience.visionforge.solid.three.ThreePlugin
|
||||
import space.kscience.visionforge.styles
|
||||
import space.kscience.visionforge.writeProperties
|
||||
|
||||
@Composable
|
||||
private fun SimpleThreeView(
|
||||
@ -137,7 +138,7 @@ public fun ThreeView(
|
||||
NameCrumbs(selected) { selected = it }
|
||||
Hr()
|
||||
PropertyEditor(
|
||||
rootMeta = vision.properties,
|
||||
rootMeta = vision.writeProperties(),
|
||||
getPropertyState = { name ->
|
||||
if (vision.properties[name] != null) {
|
||||
EditorPropertyState.Defined
|
||||
|
Reference in New Issue
Block a user