diff --git a/demo/playground/src/jvmMain/kotlin/gdmlCubes.kt b/demo/playground/src/jvmMain/kotlin/gdmlCubes.kt index fc134408..3e5b0475 100644 --- a/demo/playground/src/jvmMain/kotlin/gdmlCubes.kt +++ b/demo/playground/src/jvmMain/kotlin/gdmlCubes.kt @@ -1,20 +1,13 @@ package space.kscience.visionforge.examples import space.kscience.gdml.GdmlShowCase -import space.kscience.visionforge.Colors import space.kscience.visionforge.gdml.toVision import space.kscience.visionforge.html.ResourceLocation import space.kscience.visionforge.solid.Solids -import space.kscience.visionforge.solid.ambientLight -import space.kscience.visionforge.solid.set fun main() = makeVisionFile(resourceLocation = ResourceLocation.SYSTEM) { vision("canvas") { requirePlugin(Solids) - GdmlShowCase.cubes().toVision().also { - it.ambientLight { - color.set(Colors.white) - } - } + GdmlShowCase.cubes().toVision() } } \ No newline at end of file diff --git a/demo/playground/src/jvmMain/kotlin/gdmlCurve.kt b/demo/playground/src/jvmMain/kotlin/gdmlCurve.kt index f98a0b81..c2af2a8f 100644 --- a/demo/playground/src/jvmMain/kotlin/gdmlCurve.kt +++ b/demo/playground/src/jvmMain/kotlin/gdmlCurve.kt @@ -223,7 +223,7 @@ fun main() = makeVisionFile(Path.of("curves.html"), resourceLocation = ResourceL } } }.toVision { - configure { _, solid, _ -> + solids { _, solid, _ -> //disable visibility for the world box if(solid.name == "world"){ visible = false diff --git a/visionforge-gdml/src/commonMain/kotlin/space/kscience/visionforge/gdml/GdmlLoaderOptions.kt b/visionforge-gdml/src/commonMain/kotlin/space/kscience/visionforge/gdml/GdmlLoaderOptions.kt index 34ab7d68..56158c55 100644 --- a/visionforge-gdml/src/commonMain/kotlin/space/kscience/visionforge/gdml/GdmlLoaderOptions.kt +++ b/visionforge-gdml/src/commonMain/kotlin/space/kscience/visionforge/gdml/GdmlLoaderOptions.kt @@ -4,9 +4,7 @@ import space.kscience.dataforge.meta.Meta import space.kscience.dataforge.meta.MutableMeta import space.kscience.dataforge.names.Name import space.kscience.gdml.* -import space.kscience.visionforge.solid.Solid -import space.kscience.visionforge.solid.SolidMaterial -import space.kscience.visionforge.solid.set +import space.kscience.visionforge.solid.* import space.kscience.visionforge.useStyle import kotlin.random.Random @@ -70,7 +68,7 @@ public class GdmlLoaderOptions { } private set - public fun configure(block: Solid.(parent: GdmlVolume, solid: GdmlSolid, material: GdmlMaterial) -> Unit) { + public fun solids(block: Solid.(parent: GdmlVolume, solid: GdmlSolid, material: GdmlMaterial) -> Unit) { val oldConfigure = configureSolid configureSolid = { parent: GdmlVolume, solid: GdmlSolid, material: GdmlMaterial -> oldConfigure(parent, solid, material) @@ -79,6 +77,8 @@ public class GdmlLoaderOptions { } + public var light: LightSource? = AmbientLightSource() + public companion object { private val random: Random = Random(222) diff --git a/visionforge-gdml/src/commonMain/kotlin/space/kscience/visionforge/gdml/gdmlLoader.kt b/visionforge-gdml/src/commonMain/kotlin/space/kscience/visionforge/gdml/gdmlLoader.kt index 18e2640e..58213437 100644 --- a/visionforge-gdml/src/commonMain/kotlin/space/kscience/visionforge/gdml/gdmlLoader.kt +++ b/visionforge-gdml/src/commonMain/kotlin/space/kscience/visionforge/gdml/gdmlLoader.kt @@ -27,10 +27,10 @@ private class GdmlLoader(val settings: GdmlLoaderOptions) { /** * A special group for local templates */ - private val proto = SolidGroup() + private val templates = SolidGroup() - private val solids = proto.solidGroup(solidsName) { - properties["edges.enabled"] = false + private val solids = templates.solidGroup(solidsName) { + edges(false) } private val referenceStore = HashMap>() @@ -46,7 +46,7 @@ private class GdmlLoader(val settings: GdmlLoaderOptions) { private fun proxySolid(root: Gdml, group: SolidGroup, solid: GdmlSolid, name: String): SolidReference { val templateName = solidsName + name - if (proto[templateName] == null) { + if (templates[templateName] == null) { solids.addSolid(root, solid, name) } val ref = group.ref(templateName, name) @@ -61,8 +61,8 @@ private class GdmlLoader(val settings: GdmlLoaderOptions) { volume: GdmlGroup, ): SolidReference { val templateName = volumesName + volume.name.asName() - if (proto[templateName] == null) { - proto.setChild(templateName, volume(root, volume)) + if (templates[templateName] == null) { + templates.setChild(templateName, volume(root, volume)) } val ref = group.ref(templateName, physVolume.name).withPosition(root, physVolume) referenceStore.getOrPut(templateName) { ArrayList() }.add(ref) @@ -139,6 +139,7 @@ private class GdmlLoader(val settings: GdmlLoaderOptions) { angle = solid.deltaphi * aScale, name = name ) + is GdmlCone -> if (solid.rmin1.toDouble() == 0.0 && solid.rmin2.toDouble() == 0.0) { cone( bottomRadius = solid.rmax1 * lScale, @@ -160,6 +161,7 @@ private class GdmlLoader(val settings: GdmlLoaderOptions) { name = name ) } + is GdmlXtru -> extruded(name) { shape { solid.vertices.forEach { @@ -175,6 +177,7 @@ private class GdmlLoader(val settings: GdmlLoaderOptions) { ) } } + is GdmlScaledSolid -> { //Add solid with modified scale val innerSolid: GdmlSolid = solid.solidref.resolve(root) @@ -186,6 +189,7 @@ private class GdmlLoader(val settings: GdmlLoaderOptions) { scaleZ = solid.scale.z.toFloat() } } + is GdmlSphere -> sphereLayer( outerRadius = solid.rmax * lScale, innerRadius = solid.rmin * lScale, @@ -195,6 +199,7 @@ private class GdmlLoader(val settings: GdmlLoaderOptions) { thetaStart = solid.starttheta * aScale, name = name, ) + is GdmlOrb -> sphere(solid.r * lScale, name = name) is GdmlPolyhedra -> extruded(name) { //getting the radius of first @@ -211,6 +216,7 @@ private class GdmlLoader(val settings: GdmlLoaderOptions) { layer(plane.z * lScale, scale = plane.rmax * lScale / baseRadius) } } + is GdmlBoolSolid -> { val first: GdmlSolid = solid.first.resolve(root) ?: error("") val second: GdmlSolid = solid.second.resolve(root) ?: error("") @@ -235,6 +241,7 @@ private class GdmlLoader(val settings: GdmlLoaderOptions) { } } + is GdmlTrapezoid -> { val dxBottom = solid.x1.toDouble() / 2 val dxTop = solid.x2.toDouble() / 2 @@ -251,6 +258,7 @@ private class GdmlLoader(val settings: GdmlLoaderOptions) { val node8 = Point3D(-dxTop, dyTop, dz) hexagon(node1, node2, node3, node4, node5, node6, node7, node8, name) } + is GdmlEllipsoid -> TODO("Renderer for $solid not supported yet") is GdmlElTube -> TODO("Renderer for $solid not supported yet") is GdmlElCone -> TODO("Renderer for $solid not supported yet") @@ -271,9 +279,11 @@ private class GdmlLoader(val settings: GdmlLoaderOptions) { GdmlLoaderOptions.Action.ADD -> { addSolid(root, solid, name) } + GdmlLoaderOptions.Action.PROTOTYPE -> { proxySolid(root, this, solid, name ?: solid.name) } + GdmlLoaderOptions.Action.REJECT -> { //ignore null @@ -304,9 +314,11 @@ private class GdmlLoader(val settings: GdmlLoaderOptions) { val group: SolidGroup = volume(root, volume) this.setChild(physVolume.name, group.withPosition(root, physVolume)) } + GdmlLoaderOptions.Action.PROTOTYPE -> { proxyVolume(root, this, physVolume, volume) } + GdmlLoaderOptions.Action.REJECT -> { //ignore } @@ -348,35 +360,36 @@ private class GdmlLoader(val settings: GdmlLoaderOptions) { } } - private fun finalize(final: SolidGroup): SolidGroup { - val rootStyle by final.style("gdml") { + fun transform(root: Gdml): SolidGroup { + val rootSolid = volume(root, root.world.resolve(root) ?: error("GDML root is not resolved")) + + val rootStyle by rootSolid.style("gdml") { Solid.ROTATION_ORDER_KEY put RotationOrder.ZXY } - final.useStyle(rootStyle, false) - final.prototypes { - proto.items.forEach { (token, item) -> + rootSolid.useStyle(rootStyle, false) + + rootSolid.prototypes { + templates.items.forEach { (token, item) -> item.parent = null setChild(token.asName(), item as? Solid) } } settings.styleCache.forEach { - final.styleSheet { + rootSolid.styleSheet { define(it.key.toString(), it.value) } } - return final + return rootSolid } - - fun transform(root: Gdml): SolidGroup = - finalize(volume(root, root.world.resolve(root) ?: error("GDML root is not resolved"))) } public fun Gdml.toVision(block: GdmlLoaderOptions.() -> Unit = {}): SolidGroup { val settings = GdmlLoaderOptions().apply(block) - val context = GdmlLoader(settings) - return context.transform(this) + return GdmlLoader(settings).transform(this).also { + it.children["light"] = settings.light + } } /** diff --git a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/ColorAccessor.kt b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/ColorAccessor.kt index 29de1575..01abf310 100644 --- a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/ColorAccessor.kt +++ b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/ColorAccessor.kt @@ -28,8 +28,10 @@ public class ColorAccessor( } } -public fun Vision.color(): ReadOnlyProperty = ReadOnlyProperty { _, property -> - ColorAccessor(properties.root(true), property.name.asName()) +public fun Vision.color( + propertyName: Name? = null, +): ReadOnlyProperty = ReadOnlyProperty { _, property -> + ColorAccessor(properties.root(true), propertyName ?: property.name.asName()) } public var ColorAccessor?.string: String? diff --git a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/LightSource.kt b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/LightSource.kt index 3db461ef..95aca618 100644 --- a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/LightSource.kt +++ b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/LightSource.kt @@ -7,16 +7,20 @@ import space.kscience.dataforge.meta.descriptors.MetaDescriptor import space.kscience.dataforge.meta.descriptors.node import space.kscience.dataforge.meta.descriptors.value import space.kscience.dataforge.meta.number +import space.kscience.dataforge.names.Name +import space.kscience.dataforge.names.asName import space.kscience.visionforge.* @Serializable public abstract class LightSource : SolidBase() { override val descriptor: MetaDescriptor get() = LightSource.descriptor - public val color: ColorAccessor by color() - public var intensity: Number by properties.root(includeStyles = false).number { 1.0 } + public val color: ColorAccessor by color(SolidMaterial.COLOR_KEY) + public var intensity: Number by properties.root(includeStyles = false).number(INTENSITY_KEY) { 1.0 } + + public companion object { + public val INTENSITY_KEY: Name = "intensity".asName() - public companion object{ public val descriptor: MetaDescriptor by lazy { MetaDescriptor { value(Vision.VISIBLE_KEY, ValueType.BOOLEAN) { @@ -27,6 +31,7 @@ public abstract class LightSource : SolidBase() { value(LightSource::color.name, ValueType.STRING, ValueType.NUMBER) { inherited = false widgetType = "color" + default(Colors.white) } value(LightSource::intensity.name, ValueType.NUMBER) { @@ -34,11 +39,6 @@ public abstract class LightSource : SolidBase() { default(1.0) } - value(SolidMaterial.COLOR_KEY, ValueType.STRING, ValueType.NUMBER) { - inherited = false - widgetType = "color" - } - node(Solid.POSITION_KEY) { hide() } diff --git a/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeAmbientLightFactory.kt b/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeAmbientLightFactory.kt index 3d420570..3f8e251c 100644 --- a/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeAmbientLightFactory.kt +++ b/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeAmbientLightFactory.kt @@ -1,6 +1,12 @@ package space.kscience.visionforge.solid.three +import space.kscience.dataforge.names.Name +import space.kscience.visionforge.Vision +import space.kscience.visionforge.onPropertyChange import space.kscience.visionforge.solid.AmbientLightSource +import space.kscience.visionforge.solid.LightSource +import space.kscience.visionforge.solid.SolidMaterial +import space.kscience.visionforge.visible import three.lights.AmbientLight import three.math.Color import kotlin.reflect.KClass @@ -14,6 +20,16 @@ public object ThreeAmbientLightFactory : ThreeFactory { intensity = vision.intensity.toDouble() } + if (observe) { + vision.onPropertyChange(three.context) { propertyName: Name -> + when (propertyName) { + Vision.VISIBLE_KEY -> res.visible = vision.visible ?: true + SolidMaterial.COLOR_KEY -> res.color = vision.color.threeColor() ?: Color(0x404040) + LightSource.INTENSITY_KEY -> res.intensity = vision.intensity.toDouble() + } + } + } + return res } } \ No newline at end of file diff --git a/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeMeshFactory.kt b/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeMeshFactory.kt index b3281e4b..30f3034b 100644 --- a/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeMeshFactory.kt +++ b/visionforge-threejs/src/main/kotlin/space/kscience/visionforge/solid/three/ThreeMeshFactory.kt @@ -29,8 +29,6 @@ public abstract class ThreeMeshFactory( override fun build(three: ThreePlugin, vision: T, observe: Boolean): Mesh { val geometry = buildGeometry(vision) - //val meshMeta: Meta = obj.properties[Material3D.MATERIAL_KEY]?.node ?: Meta.empty - val mesh = Mesh(geometry, ThreeMaterials.DEFAULT).apply { matrixAutoUpdate = false //set position for mesh @@ -46,11 +44,10 @@ public abstract class ThreeMeshFactory( val oldGeometry = mesh.geometry val newGeometry = buildGeometry(vision) oldGeometry.attributes = newGeometry.attributes - //mesh.applyWireFrame(obj) + mesh.applyEdges(vision) newGeometry.dispose() } - //name.startsWith(WIREFRAME_KEY) -> mesh.applyWireFrame(obj) name.startsWith(EDGES_KEY) -> mesh.applyEdges(vision) else -> mesh.updateProperty(vision, name) } @@ -62,18 +59,12 @@ public abstract class ThreeMeshFactory( public companion object { internal const val EDGES_OBJECT_NAME: String = "@edges" - - //public val WIREFRAME_KEY: Name = "wireframe".asName() - - //public val WIREFRAME_ENABLED_KEY: Name = WIREFRAME_KEY + ENABLED_KEY - //public val WIREFRAME_MATERIAL_KEY: Name = WIREFRAME_KEY + SolidMaterial.MATERIAL_KEY } } internal fun Mesh.applyProperties(vision: Solid): Mesh = apply { setMaterial(vision) applyEdges(vision) - //applyWireFrame(obj) layers.set(vision.layer) children.forEach { it.layers.set(vision.layer) @@ -104,24 +95,3 @@ public fun Mesh.applyEdges(vision: Solid) { } } } - -//public fun Mesh.applyWireFrame(obj: Solid) { -// children.find { it.name == "@wireframe" }?.let { -// remove(it) -// (it as LineSegments).dispose() -// } -// //inherited wireframe definition, disabled by default -// if (obj.getProperty(MeshThreeFactory.WIREFRAME_ENABLED_KEY).boolean == true) { -// val bufferGeometry = geometry as? BufferGeometry ?: return -// val material = -// ThreeMaterials.getLineMaterial(obj.getProperty(MeshThreeFactory.WIREFRAME_MATERIAL_KEY).node, true) -// add( -// LineSegments( -// WireframeGeometry(bufferGeometry), -// material -// ).apply { -// name = "@wireframe" -// } -// ) -// } -//} \ No newline at end of file