Suspended renderers and property change listeners

This commit is contained in:
Alexander Nozik 2023-06-04 20:58:03 +03:00
parent 8204eb63c3
commit 2b70afdb86
15 changed files with 93 additions and 32 deletions

View File

@ -8,7 +8,7 @@ kscience{
kotlin{ kotlin{
explicitApi = null explicitApi = null
js(IR){ js{
useCommonJs() useCommonJs()
browser { browser {
binaries.executable() binaries.executable()

View File

@ -1,14 +1,14 @@
plugins { plugins {
id("space.kscience.gradle.mpp") id("space.kscience.gradle.mpp")
application // application
} }
kscience { kscience {
useCoroutines() useCoroutines()
jvm { jvm()
withJava() js{
binaries.executable()
} }
js()
dependencies { dependencies {
implementation(projects.visionforgeSolid) implementation(projects.visionforgeSolid)
implementation(projects.visionforgeGdml) implementation(projects.visionforgeGdml)
@ -21,6 +21,6 @@ kscience {
kotlin.explicitApi = null kotlin.explicitApi = null
application { //application {
mainClass.set("space.kscience.visionforge.solid.demo.FXDemoAppKt") // mainClass.set("space.kscience.visionforge.solid.demo.FXDemoAppKt")
} //}

View File

@ -150,6 +150,10 @@ fun VisionLayout<Solid>.showcase() {
z = 26 z = 26
} }
} }
demo("STL", "STL loaded from URL"){
stl("https://ozeki.hu/attachments/116/Menger_sponge_sample.stl")
}
} }
fun VisionLayout<Solid>.showcaseCSG() { fun VisionLayout<Solid>.showcaseCSG() {

View File

@ -67,7 +67,7 @@ public var Vision.visible: Boolean?
*/ */
public fun Vision.onPropertyChange( public fun Vision.onPropertyChange(
scope: CoroutineScope? = manager?.context, scope: CoroutineScope? = manager?.context,
callback: (Name) -> Unit callback: suspend (Name) -> Unit
): Job = properties.changes.onEach { ): Job = properties.changes.onEach {
callback(it) callback(it)
}.launchIn(scope ?: error("Orphan Vision can't observe properties")) }.launchIn(scope ?: error("Orphan Vision can't observe properties"))

View File

@ -0,0 +1,25 @@
package space.kscience.visionforge.solid
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import space.kscience.visionforge.MutableVisionContainer
import space.kscience.visionforge.VisionBuilder
import space.kscience.visionforge.setChild
public sealed class StlVision: SolidBase<StlVision>()
@Serializable
@SerialName("solid.stl.url")
public class StlUrlVision(public val url: String) : StlVision()
@Serializable
@SerialName("solid.stl.binary")
public class StlBinaryVision(public val data: ByteArray) : StlVision()
@VisionBuilder
public inline fun MutableVisionContainer<Solid>.stl(
url: String,
name: String? = null,
action: StlVision.() -> Unit = {},
): StlVision = StlUrlVision(url).apply(action).also { setChild(name, it) }

View File

@ -5,7 +5,7 @@ import space.kscience.visionforge.solid.detail
import three.geometries.BoxGeometry import three.geometries.BoxGeometry
public object ThreeBoxFactory : ThreeMeshFactory<Box>(Box::class) { public object ThreeBoxFactory : ThreeMeshFactory<Box>(Box::class) {
override fun buildGeometry(obj: Box): BoxGeometry = override suspend fun buildGeometry(obj: Box): BoxGeometry =
obj.detail?.let { detail -> obj.detail?.let { detail ->
BoxGeometry(obj.xSize, obj.ySize, obj.zSize, detail, detail, detail) BoxGeometry(obj.xSize, obj.ySize, obj.zSize, detail, detail, detail)
} ?: BoxGeometry(obj.xSize, obj.ySize, obj.zSize) } ?: BoxGeometry(obj.xSize, obj.ySize, obj.zSize)

View File

@ -8,7 +8,7 @@ import kotlin.math.PI
import kotlin.math.pow import kotlin.math.pow
public object ThreeConeFactory : ThreeMeshFactory<ConeSegment>(ConeSegment::class) { public object ThreeConeFactory : ThreeMeshFactory<ConeSegment>(ConeSegment::class) {
override fun buildGeometry(obj: ConeSegment): BufferGeometry { override suspend fun buildGeometry(obj: ConeSegment): BufferGeometry {
val cylinder = obj.detail?.let { val cylinder = obj.detail?.let {
val segments = it.toDouble().pow(0.5).toInt() val segments = it.toDouble().pow(0.5).toInt()
CylinderGeometry( CylinderGeometry(

View File

@ -4,7 +4,7 @@ import space.kscience.visionforge.solid.Convex
import three.external.geometries.ConvexBufferGeometry import three.external.geometries.ConvexBufferGeometry
public object ThreeConvexFactory : ThreeMeshFactory<Convex>(Convex::class) { public object ThreeConvexFactory : ThreeMeshFactory<Convex>(Convex::class) {
override fun buildGeometry(obj: Convex): ConvexBufferGeometry { override suspend fun buildGeometry(obj: Convex): ConvexBufferGeometry {
val vectors = obj.points.map { it.toVector() }.toTypedArray() val vectors = obj.points.map { it.toVector() }.toTypedArray()
return ConvexBufferGeometry(vectors) return ConvexBufferGeometry(vectors)
} }

View File

@ -84,7 +84,7 @@ public fun Object3D.updateProperty(source: Vision, propertyName: Name) {
* Generic factory for elements which provide inside geometry builder * Generic factory for elements which provide inside geometry builder
*/ */
public object ThreeShapeFactory : ThreeMeshFactory<GeometrySolid>(GeometrySolid::class) { public object ThreeShapeFactory : ThreeMeshFactory<GeometrySolid>(GeometrySolid::class) {
override fun buildGeometry(obj: GeometrySolid): BufferGeometry = ThreeGeometryBuilder().apply { override suspend fun buildGeometry(obj: GeometrySolid): BufferGeometry = ThreeGeometryBuilder().apply {
obj.toGeometry(this) obj.toGeometry(this)
}.build() }.build()
} }

View File

@ -1,6 +1,5 @@
package space.kscience.visionforge.solid.three package space.kscience.visionforge.solid.three
import org.w3c.dom.url.URL
import space.kscience.visionforge.solid.SolidBase import space.kscience.visionforge.solid.SolidBase
import three.core.Object3D import three.core.Object3D
@ -10,15 +9,3 @@ import three.core.Object3D
public abstract class ThreeJsVision : SolidBase<ThreeJsVision>() { public abstract class ThreeJsVision : SolidBase<ThreeJsVision>() {
public abstract suspend fun render(three: ThreePlugin): Object3D public abstract suspend fun render(three: ThreePlugin): Object3D
} }
public class ThreeStlVision(val url: URL): ThreeJsVision(){
override suspend fun render(three: ThreePlugin): Object3D {
// suspendCoroutine {
//
// }
// STLLoader()
TODO()
}
}

View File

@ -21,10 +21,11 @@ import kotlin.reflect.KClass
public abstract class ThreeMeshFactory<in T : Solid>( public abstract class ThreeMeshFactory<in T : Solid>(
override val type: KClass<in T>, override val type: KClass<in T>,
) : ThreeFactory<T> { ) : ThreeFactory<T> {
/** /**
* Build a geometry for an object * Build a geometry for an object
*/ */
public abstract fun buildGeometry(obj: T): BufferGeometry public abstract suspend fun buildGeometry(obj: T): BufferGeometry
override suspend fun build(three: ThreePlugin, vision: T, observe: Boolean): Mesh { override suspend fun build(three: ThreePlugin, vision: T, observe: Boolean): Mesh {
val geometry = buildGeometry(vision) val geometry = buildGeometry(vision)

View File

@ -37,6 +37,7 @@ public class ThreePlugin : AbstractPlugin(), ElementVisionRenderer {
objectFactories[SolidLabel::class] = ThreeCanvasLabelFactory objectFactories[SolidLabel::class] = ThreeCanvasLabelFactory
objectFactories[AmbientLightSource::class] = ThreeAmbientLightFactory objectFactories[AmbientLightSource::class] = ThreeAmbientLightFactory
objectFactories[PointLightSource::class] = ThreePointLightFactory objectFactories[PointLightSource::class] = ThreePointLightFactory
objectFactories[StlVision::class] = ThreeStlFactory
} }
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")

View File

@ -6,7 +6,7 @@ import three.core.BufferGeometry
import three.geometries.SphereGeometry import three.geometries.SphereGeometry
public object ThreeSphereFactory : ThreeMeshFactory<Sphere>(Sphere::class) { public object ThreeSphereFactory : ThreeMeshFactory<Sphere>(Sphere::class) {
override fun buildGeometry(obj: Sphere): BufferGeometry { override suspend fun buildGeometry(obj: Sphere): BufferGeometry {
return obj.detail?.let { detail -> return obj.detail?.let { detail ->
SphereGeometry( SphereGeometry(
radius = obj.radius, radius = obj.radius,

View File

@ -0,0 +1,38 @@
package space.kscience.visionforge.solid.three
import org.khronos.webgl.ArrayBuffer
import org.khronos.webgl.Int8Array
import space.kscience.visionforge.solid.StlBinaryVision
import space.kscience.visionforge.solid.StlUrlVision
import space.kscience.visionforge.solid.StlVision
import three.core.BufferGeometry
import three.external.loaders.STLLoader
import kotlin.coroutines.resume
import kotlin.coroutines.resumeWithException
import kotlin.coroutines.suspendCoroutine
fun ArrayBuffer.toByteArray(): ByteArray = Int8Array(this).unsafeCast<ByteArray>()
public object ThreeStlFactory : ThreeMeshFactory<StlVision>(StlVision::class) {
private val loader = STLLoader().apply {
requestHeader = listOf("Access-Control-Allow-Origin: *")
}
override suspend fun buildGeometry(obj: StlVision): BufferGeometry = when (obj) {
is StlBinaryVision -> loader.parse(obj.data)
is StlUrlVision -> suspendCoroutine { continuation ->
loader.load(
url = obj.url,
onLoad = {
continuation.resume(it)
},
onError = {
continuation.resumeWithException(RuntimeException("Failed to load STL object from ${obj.url}"))
}
)
}
}
}

View File

@ -22,17 +22,19 @@
* THE SOFTWARE. * THE SOFTWARE.
*/ */
@file:JsModule("three") @file:JsModule("three/examples/jsm/loaders/STLLoader.js")
@file:JsNonModule @file:JsNonModule
package three.external.loaders package three.external.loaders
import org.khronos.webgl.ArrayBuffer
import org.w3c.xhr.XMLHttpRequest import org.w3c.xhr.XMLHttpRequest
import three.core.BufferGeometry import three.core.BufferGeometry
import three.core.Object3D
external class STLLoader { external class STLLoader {
var requestHeader: List<String>
fun load( fun load(
url: String, url: String,
onLoad: (BufferGeometry) -> Unit, onLoad: (BufferGeometry) -> Unit,
@ -40,7 +42,10 @@ external class STLLoader {
onError: () -> Unit = definedExternally onError: () -> Unit = definedExternally
) )
fun parse(data: String): Object3D fun parse(data: String): BufferGeometry
fun parse(data: ByteArray): Object3D
fun parse(data: ByteArray): BufferGeometry
fun parse(data: ArrayBuffer): BufferGeometry
} }