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{
explicitApi = null
js(IR){
js{
useCommonJs()
browser {
binaries.executable()

View File

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

View File

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

View File

@ -67,7 +67,7 @@ public var Vision.visible: Boolean?
*/
public fun Vision.onPropertyChange(
scope: CoroutineScope? = manager?.context,
callback: (Name) -> Unit
callback: suspend (Name) -> Unit
): Job = properties.changes.onEach {
callback(it)
}.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
public object ThreeBoxFactory : ThreeMeshFactory<Box>(Box::class) {
override fun buildGeometry(obj: Box): BoxGeometry =
override suspend fun buildGeometry(obj: Box): BoxGeometry =
obj.detail?.let { detail ->
BoxGeometry(obj.xSize, obj.ySize, obj.zSize, detail, detail, detail)
} ?: BoxGeometry(obj.xSize, obj.ySize, obj.zSize)

View File

@ -8,7 +8,7 @@ import kotlin.math.PI
import kotlin.math.pow
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 segments = it.toDouble().pow(0.5).toInt()
CylinderGeometry(

View File

@ -4,7 +4,7 @@ import space.kscience.visionforge.solid.Convex
import three.external.geometries.ConvexBufferGeometry
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()
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
*/
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)
}.build()
}

View File

@ -1,6 +1,5 @@
package space.kscience.visionforge.solid.three
import org.w3c.dom.url.URL
import space.kscience.visionforge.solid.SolidBase
import three.core.Object3D
@ -10,15 +9,3 @@ import three.core.Object3D
public abstract class ThreeJsVision : SolidBase<ThreeJsVision>() {
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>(
override val type: KClass<in T>,
) : ThreeFactory<T> {
/**
* 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 {
val geometry = buildGeometry(vision)

View File

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

View File

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