FX backend in progress
This commit is contained in:
parent
cef1a1ee6d
commit
fd43ea4843
@ -1,8 +1,10 @@
|
|||||||
package hep.dataforge.vis.spatial.fx
|
package hep.dataforge.vis.spatial.demo
|
||||||
|
|
||||||
import hep.dataforge.context.Global
|
import hep.dataforge.context.Global
|
||||||
import hep.dataforge.meta.number
|
import hep.dataforge.meta.number
|
||||||
import hep.dataforge.vis.spatial.*
|
import hep.dataforge.vis.spatial.*
|
||||||
|
import hep.dataforge.vis.spatial.fx.Canvas3D
|
||||||
|
import hep.dataforge.vis.spatial.fx.FX3DPlugin
|
||||||
import javafx.scene.Parent
|
import javafx.scene.Parent
|
||||||
import kotlinx.coroutines.GlobalScope
|
import kotlinx.coroutines.GlobalScope
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
@ -11,22 +13,21 @@ import kotlinx.coroutines.launch
|
|||||||
import tornadofx.*
|
import tornadofx.*
|
||||||
import kotlin.random.Random
|
import kotlin.random.Random
|
||||||
|
|
||||||
|
class SpatialDemoApp: App(SpatialDemoView::class)
|
||||||
|
|
||||||
class RendererDemoApp : App(RendererDemoView::class)
|
class SpatialDemoView: View(){
|
||||||
|
private val plugin = Global.plugins.fetch(FX3DPlugin)
|
||||||
|
private val canvas = Canvas3D(plugin)
|
||||||
|
|
||||||
|
|
||||||
class RendererDemoView : View() {
|
|
||||||
val plugin = Global.plugins.fetch(FX3DPlugin)
|
|
||||||
val renderer = Canvas3D(plugin)
|
|
||||||
override val root: Parent = borderpane {
|
override val root: Parent = borderpane {
|
||||||
center = renderer.root
|
center = canvas.root
|
||||||
}
|
}
|
||||||
|
|
||||||
lateinit var group: VisualGroup3D
|
lateinit var group: VisualGroup3D
|
||||||
|
|
||||||
init {
|
init {
|
||||||
|
canvas.render {
|
||||||
renderer.render {
|
box(100,100,100)
|
||||||
group = group {
|
group = group {
|
||||||
box(100,100,100)
|
box(100,100,100)
|
||||||
box(100,100,100) {
|
box(100,100,100) {
|
||||||
@ -45,7 +46,7 @@ class RendererDemoView : View() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
renderer.apply {
|
canvas.apply {
|
||||||
angleY = -30.0
|
angleY = -30.0
|
||||||
angleX = -15.0
|
angleX = -15.0
|
||||||
}
|
}
|
||||||
@ -54,5 +55,5 @@ class RendererDemoView : View() {
|
|||||||
|
|
||||||
|
|
||||||
fun main() {
|
fun main() {
|
||||||
launch<RendererDemoApp>()
|
launch<SpatialDemoApp>()
|
||||||
}
|
}
|
@ -19,13 +19,21 @@ import javafx.scene.input.KeyEvent
|
|||||||
import javafx.scene.input.MouseEvent
|
import javafx.scene.input.MouseEvent
|
||||||
import javafx.scene.input.ScrollEvent
|
import javafx.scene.input.ScrollEvent
|
||||||
import javafx.scene.paint.Color
|
import javafx.scene.paint.Color
|
||||||
|
import org.fxyz3d.scene.Axes
|
||||||
|
import org.fxyz3d.scene.CubeWorld
|
||||||
import org.fxyz3d.utils.CameraTransformer
|
import org.fxyz3d.utils.CameraTransformer
|
||||||
import tornadofx.*
|
import tornadofx.*
|
||||||
|
|
||||||
class Canvas3D(val plugin: FX3DPlugin, val meta: Meta = EmptyMeta) : Fragment(), Renderer<VisualObject3D>, ContextAware {
|
class Canvas3D(val plugin: FX3DPlugin, meta: Meta = EmptyMeta) :
|
||||||
|
Fragment(), Renderer<VisualObject3D>, ContextAware {
|
||||||
|
|
||||||
override val context: Context get() = plugin.context
|
override val context: Context get() = plugin.context
|
||||||
val world: Group = Group()
|
val world = CubeWorld(true)
|
||||||
|
val axes = Axes().also {
|
||||||
|
it.setHeight(AXIS_LENGTH)
|
||||||
|
it.setRadius(LINE_WIDTH)
|
||||||
|
world.add(it)
|
||||||
|
}
|
||||||
|
|
||||||
private val camera = PerspectiveCamera().apply {
|
private val camera = PerspectiveCamera().apply {
|
||||||
nearClip = CAMERA_NEAR_CLIP
|
nearClip = CAMERA_NEAR_CLIP
|
||||||
@ -69,12 +77,12 @@ class Canvas3D(val plugin: FX3DPlugin, val meta: Meta = EmptyMeta) : Fragment(),
|
|||||||
768.0,
|
768.0,
|
||||||
true,
|
true,
|
||||||
SceneAntialiasing.BALANCED
|
SceneAntialiasing.BALANCED
|
||||||
).apply {
|
).also {scene->
|
||||||
fill = Color.GREY
|
scene.fill = Color.GREY
|
||||||
this.camera = this@Canvas3D.camera
|
scene.camera = camera
|
||||||
id = "canvas"
|
id = "canvas"
|
||||||
handleKeyboard(this)
|
handleKeyboard(scene)
|
||||||
handleMouse(this)
|
handleMouse(scene)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -90,7 +98,7 @@ class Canvas3D(val plugin: FX3DPlugin, val meta: Meta = EmptyMeta) : Fragment(),
|
|||||||
cameraRotation.ry.angle = CAMERA_INITIAL_Y_ANGLE
|
cameraRotation.ry.angle = CAMERA_INITIAL_Y_ANGLE
|
||||||
cameraRotation.rx.angle = CAMERA_INITIAL_X_ANGLE
|
cameraRotation.rx.angle = CAMERA_INITIAL_X_ANGLE
|
||||||
}
|
}
|
||||||
// KeyCode.X -> axisGroup.isVisible = !axisGroup.isVisible
|
KeyCode.X -> axes.isVisible = !axes.isVisible
|
||||||
// KeyCode.S -> snapshot()
|
// KeyCode.S -> snapshot()
|
||||||
// KeyCode.DIGIT1 -> pixelMap.filterKeys { it.getLayerNumber() == 1 }.values.forEach {
|
// KeyCode.DIGIT1 -> pixelMap.filterKeys { it.getLayerNumber() == 1 }.values.forEach {
|
||||||
// toggleTransparency(
|
// toggleTransparency(
|
||||||
@ -145,8 +153,8 @@ class Canvas3D(val plugin: FX3DPlugin, val meta: Meta = EmptyMeta) : Fragment(),
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (me.isPrimaryButtonDown) {
|
if (me.isPrimaryButtonDown) {
|
||||||
cameraRotation.rz.angle =
|
cameraRotation.ry.angle =
|
||||||
cameraRotation.rz.angle + mouseDeltaX * MOUSE_SPEED * modifier * ROTATION_SPEED
|
cameraRotation.ry.angle + mouseDeltaX * MOUSE_SPEED * modifier * ROTATION_SPEED
|
||||||
cameraRotation.rx.angle =
|
cameraRotation.rx.angle =
|
||||||
cameraRotation.rx.angle + mouseDeltaY * MOUSE_SPEED * modifier * ROTATION_SPEED
|
cameraRotation.rx.angle + mouseDeltaY * MOUSE_SPEED * modifier * ROTATION_SPEED
|
||||||
} else if (me.isSecondaryButtonDown) {
|
} else if (me.isSecondaryButtonDown) {
|
||||||
@ -162,7 +170,8 @@ class Canvas3D(val plugin: FX3DPlugin, val meta: Meta = EmptyMeta) : Fragment(),
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun render(obj: VisualObject3D, meta: Meta) {
|
override fun render(obj: VisualObject3D, meta: Meta) {
|
||||||
plugin.buildNode(obj)?.let { world.children.add(it) }
|
val node = plugin.buildNode(obj) ?: kotlin.error("Can't render FX node for object $obj")
|
||||||
|
world.add(node)
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
@ -84,7 +84,7 @@ class FX3DPlugin : AbstractPlugin() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (this is Shape3D) {
|
if (this is Shape3D) {
|
||||||
materialProperty().bind(binding["color"].transform { it.material() })
|
materialProperty().bind(binding[Material3D.MATERIAL_KEY].transform { it.material() })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,7 @@ import javafx.scene.paint.Color
|
|||||||
import javafx.scene.paint.Material
|
import javafx.scene.paint.Material
|
||||||
import javafx.scene.paint.PhongMaterial
|
import javafx.scene.paint.PhongMaterial
|
||||||
|
|
||||||
object Materials {
|
object FXMaterials {
|
||||||
val RED = PhongMaterial().apply {
|
val RED = PhongMaterial().apply {
|
||||||
diffuseColor = Color.DARKRED
|
diffuseColor = Color.DARKRED
|
||||||
specularColor = Color.RED
|
specularColor = Color.RED
|
||||||
@ -30,8 +30,9 @@ object Materials {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Infer color based on meta item
|
* Infer color based on meta item
|
||||||
|
* @param opacity default opacity
|
||||||
*/
|
*/
|
||||||
fun MetaItem<*>.color(): Color {
|
fun MetaItem<*>.color(opacity: Double = 1.0): Color {
|
||||||
return when (this) {
|
return when (this) {
|
||||||
is MetaItem.ValueItem -> if (this.value.type == ValueType.STRING) {
|
is MetaItem.ValueItem -> if (this.value.type == ValueType.STRING) {
|
||||||
Color.web(this.value.string)
|
Color.web(this.value.string)
|
||||||
@ -47,7 +48,7 @@ fun MetaItem<*>.color(): Color {
|
|||||||
node["red"]?.int ?: 0,
|
node["red"]?.int ?: 0,
|
||||||
node["green"]?.int ?: 0,
|
node["green"]?.int ?: 0,
|
||||||
node["blue"]?.int ?: 0,
|
node["blue"]?.int ?: 0,
|
||||||
node["opacity"]?.double ?: 1.0
|
node["opacity"]?.double ?: opacity
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -58,11 +59,13 @@ fun MetaItem<*>.color(): Color {
|
|||||||
*/
|
*/
|
||||||
fun MetaItem<*>?.material(): Material {
|
fun MetaItem<*>?.material(): Material {
|
||||||
return when (this) {
|
return when (this) {
|
||||||
null -> Materials.GREY
|
null -> FXMaterials.GREY
|
||||||
is MetaItem.ValueItem -> PhongMaterial(color())
|
is MetaItem.ValueItem -> PhongMaterial(color())
|
||||||
is MetaItem.NodeItem -> PhongMaterial().apply {
|
is MetaItem.NodeItem -> PhongMaterial().apply {
|
||||||
(node["color"]?: this@material).let { diffuseColor = it.color() }
|
val opacity = node["opacity"].double ?: 1.0
|
||||||
node["specularColor"]?.let { specularColor = it.color() }
|
(node["color"] ?: this@material).let { diffuseColor = it.color(opacity) }
|
||||||
|
node["specularColor"]?.let { specularColor = it.color(opacity) }
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -7,6 +7,7 @@ import hep.dataforge.vis.spatial.Shape
|
|||||||
import javafx.scene.shape.Mesh
|
import javafx.scene.shape.Mesh
|
||||||
import javafx.scene.shape.MeshView
|
import javafx.scene.shape.MeshView
|
||||||
import javafx.scene.shape.TriangleMesh
|
import javafx.scene.shape.TriangleMesh
|
||||||
|
import org.fxyz3d.geometry.Face3
|
||||||
import kotlin.reflect.KClass
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
object FXShapeFactory : FX3DFactory<Shape> {
|
object FXShapeFactory : FX3DFactory<Shape> {
|
||||||
@ -18,11 +19,9 @@ object FXShapeFactory : FX3DFactory<Shape> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private typealias Face = IntArray
|
|
||||||
|
|
||||||
private class FXGeometryBuilder : GeometryBuilder<Mesh> {
|
private class FXGeometryBuilder : GeometryBuilder<Mesh> {
|
||||||
val vertices = ArrayList<Point3D>()
|
val vertices = ArrayList<Point3D>()
|
||||||
val faces = ArrayList<Face>()
|
val faces = ArrayList<Face3>()
|
||||||
private val vertexCache = HashMap<Point3D, Int>()
|
private val vertexCache = HashMap<Point3D, Int>()
|
||||||
|
|
||||||
private fun append(vertex: Point3D): Int {
|
private fun append(vertex: Point3D): Int {
|
||||||
@ -38,7 +37,7 @@ private class FXGeometryBuilder : GeometryBuilder<Mesh> {
|
|||||||
|
|
||||||
override fun face(vertex1: Point3D, vertex2: Point3D, vertex3: Point3D, normal: Point3D?, meta: Meta) {
|
override fun face(vertex1: Point3D, vertex2: Point3D, vertex3: Point3D, normal: Point3D?, meta: Meta) {
|
||||||
//adding vertices
|
//adding vertices
|
||||||
val face: Face = intArrayOf(append(vertex1), append(vertex2), append(vertex3))
|
val face = Face3(append(vertex1), append(vertex2), append(vertex3))
|
||||||
faces.add(face)
|
faces.add(face)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -49,7 +48,7 @@ private class FXGeometryBuilder : GeometryBuilder<Mesh> {
|
|||||||
mesh.points.addAll(it.x.toFloat(), it.y.toFloat(), it.z.toFloat())
|
mesh.points.addAll(it.x.toFloat(), it.y.toFloat(), it.z.toFloat())
|
||||||
}
|
}
|
||||||
faces.forEach {
|
faces.forEach {
|
||||||
mesh.faces.addAll(it[0], it[1], it[2])
|
mesh.faces.addAll(it.p0, it.p1, it.p2)
|
||||||
}
|
}
|
||||||
return mesh
|
return mesh
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user