Skip to content

Commit

Permalink
Merge pull request #224 from scenerygraphics/bdv-integration-multi
Browse files Browse the repository at this point in the history
Initial integration of BigDataViewer/BigVolumeViewer.
  • Loading branch information
skalarproduktraum committed Jan 7, 2019
2 parents 9b5398f + de35168 commit fdf1ffd
Show file tree
Hide file tree
Showing 47 changed files with 3,733 additions and 581 deletions.
30 changes: 25 additions & 5 deletions pom.xml
Expand Up @@ -10,7 +10,7 @@

<groupId>graphics.scenery</groupId>
<artifactId>scenery</artifactId>
<version>0.6.3-SNAPSHOT</version>
<version>0.7.0-SNAPSHOT</version>

<name>scenery</name>
<description>flexible scenegraphing and rendering for scientific visualisation</description>
Expand Down Expand Up @@ -99,16 +99,16 @@
<properties>
<scijava.jvm.version>1.8</scijava.jvm.version>
<javac.target>1.8</javac.target>
<kotlin.version>1.3.0</kotlin.version>
<kotlin.version>1.3.11</kotlin.version>
<kotlin.compiler.jvmTarget>1.8</kotlin.compiler.jvmTarget>
<kotlin.compiler.incremental>true</kotlin.compiler.incremental>
<dokka.version>0.9.17</dokka.version>
<dokka.skip>true</dokka.skip>

<cleargl.version>2.2.1</cleargl.version>
<cleargl.version>2.2.5</cleargl.version>
<slf4j.version>1.7.25</slf4j.version>
<lwjgl.version>3.2.0</lwjgl.version>
<spirvcrossj.version>0.4.2</spirvcrossj.version>
<lwjgl.version>3.2.1</lwjgl.version>
<spirvcrossj.version>0.5.0-1.1.85</spirvcrossj.version>
<jvrpn.version>1.1.0</jvrpn.version>

<license.licenseName>lgpl_v3</license.licenseName>
Expand Down Expand Up @@ -258,6 +258,15 @@
<artifactId>lwjgl-vulkan</artifactId>
<version>${lwjgl.version}</version>
</dependency>
<!-- Removed for the moment because of non-existent binaries for Linux and Windows
<dependency>
<groupId>org.lwjgl</groupId>
<artifactId>lwjgl-vulkan</artifactId>
<version>${lwjgl.version}</version>
<classifier>${lwjgl.natives}</classifier>
<scope>runtime</scope>
</dependency>
-->
<dependency>
<groupId>org.lwjgl</groupId>
<artifactId>lwjgl-opengl</artifactId>
Expand Down Expand Up @@ -404,6 +413,17 @@
<scope>test</scope>
</dependency>

<dependency>
<groupId>sc.fiji</groupId>
<artifactId>bigvolumeviewer</artifactId>
<version>0.1.2</version>
</dependency>

<dependency>
<groupId>org.lwjglx</groupId>
<artifactId>lwjgl3-awt</artifactId>
<version>0.1.1</version>
</dependency>
</dependencies>

<repositories>
Expand Down
47 changes: 43 additions & 4 deletions src/main/kotlin/graphics/scenery/GenericTexture.kt
Expand Up @@ -2,9 +2,16 @@ package graphics.scenery

import cleargl.GLTypeEnum
import cleargl.GLVector
import org.lwjgl.system.MemoryUtil
import java.io.Serializable
import java.nio.ByteBuffer

/** Data class for encapsulating partial transfers. */
data class TextureExtents(val x: Int, val y: Int, val z: Int, val w: Int, val h: Int, val d: Int)

/** Update class for partial updates. */
data class TextureUpdate(val extents: TextureExtents, val contents: ByteBuffer, var consumed: Boolean = false, var deallocate: Boolean = false)

/**
* Data class for storing renderer-agnostic textures
*
Expand All @@ -17,16 +24,48 @@ data class GenericTexture @JvmOverloads constructor(
var dimensions: GLVector,
/** The texture's number of channels */
var channels: Int = 4,
/** [NativeTypeEnum] declaring the data type stored in [contents] */
/** [GLTypeEnum] declaring the data type stored in [contents] */
var type: GLTypeEnum = GLTypeEnum.UnsignedByte,
/** Byte contents of the texture */
@Transient var contents: ByteBuffer,
@Transient var contents: ByteBuffer?,
/** Shall the texture be repeated on the U/S coordinate? */
var repeatS: Boolean = true,
/** Shall the texture be repeated on the V/T coordinate? */
var repeatT: Boolean = true,
/** Shall the texture be repeated on the W/U coordinate? */
var repeatU: Boolean = true,
/** Should the texture data be interpreted as normalized? Default is true, non-normalisation is better for volume data, though */
var normalized: Boolean = true,
/** Should mipmaps be generated? */
var mipmap: Boolean = true
) : Serializable
var mipmap: Boolean = true,
/** Linear or nearest neighbor filtering for scaling down. */
var minFilterLinear: Boolean = true,
/** Linear or nearest neighbor filtering for scaling up. */
var maxFilterLinear: Boolean = true,
/** List of [TextureUpdate]s for the currently active texture. */
var updates: ArrayList<TextureUpdate> = ArrayList()
) : Serializable {
/** Returns true if the generic texture does have any non-consumed updates */
fun hasConsumableUpdates(): Boolean {
return updates.any { !it.consumed }
}

/** Clears all consumed updates */
fun clearConsumedUpdates() {
updates.forEach { if(it.consumed && it.deallocate) { MemoryUtil.memFree(it.contents) } }
updates.removeIf { it.consumed }
}

/** Clears all updates */
fun clearUpdates() {
updates.clear()
}

/** Companion object of [GenericTexture], containing mainly constant defines */
companion object {
/** The textures to be contained in the ObjectTextures texture array */
val objectTextures = listOf("ambient", "diffuse", "specular", "normal", "alphamask", "displacement")
/** The ObjectTextures that should be mipmapped */
val mipmappedObjectTextures = listOf("ambient", "diffuse", "specular")
}
}
69 changes: 57 additions & 12 deletions src/main/kotlin/graphics/scenery/Node.kt
Expand Up @@ -13,6 +13,7 @@ import java.util.concurrent.CopyOnWriteArrayList
import java.util.concurrent.locks.ReentrantLock
import java.util.function.Consumer
import kotlin.collections.ArrayList
import kotlin.collections.HashMap
import kotlin.math.max
import kotlin.math.min
import kotlin.properties.Delegates
Expand Down Expand Up @@ -324,10 +325,11 @@ open class Node(open var name: String = "Node") : Renderable, Serializable {
}

if (needsUpdateWorld or force) {
if (this.parent == null || this.parent is Scene) {
val p = parent
if (p == null || p is Scene) {
world.copyFrom(model)
} else {
world.copyFrom(parent!!.world)
world.copyFrom(p.world)
world.mult(this.model)
}
}
Expand Down Expand Up @@ -414,22 +416,65 @@ open class Node(open var name: String = "Node") : Renderable, Serializable {
private val shaderPropertyFieldCache = HashMap<String, KProperty1<Node, *>>()
/**
* Returns the [ShaderProperty] given by [name], if it exists and is declared by
* this class or a subclass inheriting from [Node].
* this class or a subclass inheriting from [Node]. Returns null if the [name] can
* neither be found as a property, or as member of the shaderProperties HashMap the Node
* might declare.
*/
fun getShaderProperty(name: String): Any? {
return if(shaderPropertyFieldCache.containsKey(name)) {
shaderPropertyFieldCache[name]!!.get(this)
} else {
val field = this.javaClass.kotlin.memberProperties.find { it.name == name && it.findAnnotation<ShaderProperty>() != null}
// first, try to find the shader property in the cache, and either return it,
// or, if the member of the cache is the shaderProperties HashMap, return the member of it.
val f = shaderPropertyFieldCache[name]
if (f != null) {
val value = f.get(this)

return if (value !is HashMap<*, *>) {
f.get(this)
} else {
value.get(name)
}
}

if(field != null) {
field.isAccessible = true
// First fallthrough: In case the field is not in the cache, check all member properties
// containing the [ShaderProperty] annotation. If the property is found,
// cache it for performance reasons and return it.
val field = this.javaClass.kotlin.memberProperties.find { it.name == name && it.findAnnotation<ShaderProperty>() != null }

shaderPropertyFieldCache.put(name, field)
if (field != null) {
field.isAccessible = true

field.get(this)
} else {
shaderPropertyFieldCache.put(name, field)

return field.get(this)
}

// Last fallthrough: If [name] cannot be found as a property, try to locate it in the
// shaderProperties HashMap and return it. If it cannot be found here either, return null.
this.javaClass.kotlin.memberProperties
.filter { it.findAnnotation<ShaderProperty>() != null }
.forEach {
it.isAccessible = true
if(logger.isTraceEnabled) {
logger.trace("ShaderProperty of ${this@Node.name}: ${it.name} ${it.get(this)?.javaClass}")
}
}
val mappedProperties = this.javaClass.kotlin.memberProperties
.firstOrNull {
it.findAnnotation<ShaderProperty>() != null && it.get(this) is HashMap<*, *> && it.name == "shaderProperties"
}

return if (mappedProperties == null) {
logger.warn("Could not find shader property '$name' in class properties or properties map!")
null
} else {
mappedProperties.isAccessible = true

val map = mappedProperties.get(this) as? HashMap<String, Any>
if (map == null) {
logger.warn("$this: $name not found in shaderProperties hash map")
null
} else {
shaderPropertyFieldCache.put(name, mappedProperties)
map.get(name)
}
}
}
Expand Down
32 changes: 29 additions & 3 deletions src/main/kotlin/graphics/scenery/SceneryBase.kt
Expand Up @@ -2,6 +2,8 @@ package graphics.scenery

import cleargl.ClearGLDefaultEventListener
import cleargl.GLVector
import com.sun.jna.Library
import com.sun.jna.Native
import graphics.scenery.backends.Renderer
import graphics.scenery.backends.opengl.OpenGLRenderer
import graphics.scenery.controls.InputHandler
Expand All @@ -14,6 +16,7 @@ import graphics.scenery.utils.LazyLogger
import graphics.scenery.utils.Renderdoc
import graphics.scenery.utils.SceneryPanel
import graphics.scenery.utils.Statistics
import org.lwjgl.system.Platform
import org.scijava.Context
import org.scijava.ui.behaviour.ClickBehaviour
import java.lang.Boolean.parseBoolean
Expand Down Expand Up @@ -86,6 +89,21 @@ open class SceneryBase @JvmOverloads constructor(var applicationName: String,
protected var t = 0.0f
protected var shouldClose: Boolean = false

interface XLib: Library {
fun XInitThreads()

companion object {
val INSTANCE = Native.loadLibrary("X11", XLib::class.java) as XLib
}
}

init {
if(Platform.get() == Platform.LINUX) {
logger.debug("Running XInitThreads")
XLib.INSTANCE.XInitThreads()
}
}

/**
* the init function of [SceneryBase], override this in your subclass,
* e.g. for [Scene] construction and [Renderer] initialisation.
Expand Down Expand Up @@ -156,8 +174,16 @@ open class SceneryBase @JvmOverloads constructor(var applicationName: String,

// start & show REPL -- note: REPL will only exist if not running in headless mode
repl?.start()
if(!parseBoolean(System.getProperty("scenery.Headless", "false"))) {
repl?.showConsoleWindow()
thread {
val r = renderer ?: return@thread

while(!r.firstImageReady) {
Thread.sleep(100)
}

if (!parseBoolean(System.getProperty("scenery.Headless", "false"))) {
repl?.showConsoleWindow()
}
}

val statsRequested = java.lang.Boolean.parseBoolean(System.getProperty("scenery.PrintStatistics", "false"))
Expand Down Expand Up @@ -280,7 +306,7 @@ open class SceneryBase @JvmOverloads constructor(var applicationName: String,
val width = r.width
val height = r.height

val newRenderer = Renderer.createRenderer(hub, applicationName, scene, width, height, embed, config)
val newRenderer = Renderer.createRenderer(hub, applicationName, scene, width, height, embed, null, config)
hub.add(SceneryElement.Renderer, newRenderer)
loadInputHandler(newRenderer)

Expand Down
4 changes: 2 additions & 2 deletions src/main/kotlin/graphics/scenery/ShaderMaterial.kt
Expand Up @@ -15,12 +15,12 @@ class ShaderMaterial(var shaders: Shaders) : Material() {
companion object {

/** Creates a new file-based ShaderMaterial from a list of [files]. */
fun fromFiles(vararg files: String): ShaderMaterial {
@JvmStatic fun fromFiles(vararg files: String): ShaderMaterial {
return ShaderMaterial(Shaders.ShadersFromFiles(files.toList().toTypedArray()))
}

/** Creates a new file-based ShaderMaterial the simpleName of the class [clazz]. */
@JvmOverloads fun fromClass(clazz: Class<*>, types: List<ShaderType> = listOf(ShaderType.VertexShader, ShaderType.FragmentShader)): ShaderMaterial {
@JvmStatic @JvmOverloads fun fromClass(clazz: Class<*>, types: List<ShaderType> = listOf(ShaderType.VertexShader, ShaderType.FragmentShader)): ShaderMaterial {
return ShaderMaterial(Shaders.ShadersFromClassName(clazz, types))
}
}
Expand Down
16 changes: 10 additions & 6 deletions src/main/kotlin/graphics/scenery/backends/Renderer.kt
@@ -1,5 +1,6 @@
package graphics.scenery.backends

import com.jogamp.opengl.GLAutoDrawable
import graphics.scenery.Hub
import graphics.scenery.Hubable
import graphics.scenery.Scene
Expand All @@ -9,7 +10,6 @@ import graphics.scenery.backends.vulkan.VulkanRenderer
import graphics.scenery.utils.ExtractsNatives
import graphics.scenery.utils.LazyLogger
import graphics.scenery.utils.SceneryPanel
import org.slf4j.LoggerFactory

/**
* Renderer interface. Defines the minimal set of functions a renderer has to implement.
Expand Down Expand Up @@ -177,13 +177,14 @@ abstract class Renderer : Hubable {
* @param[windowWidth] Window width for the renderer window.
* @param[windowHeight] Window height for the renderer window.
* @param[embedIn] A [SceneryWindow] to embed the renderer in, can e.g. be a JavaFX window.
* @param[embedInDrawable] A [GLAutoDrawable] to embed the renderer in. [embedIn] and [embedInDrawable] are mutually exclusive.
* @param[renderConfigFile] A YAML file with the render path configuration from which a [RenderConfigReader.RenderConfig] will be created.
*
* @return A new [Renderer] instance.
*/
@JvmOverloads
@JvmStatic
fun createRenderer(hub: Hub, applicationName: String, scene: Scene, windowWidth: Int, windowHeight: Int, embedIn: SceneryPanel? = null, renderConfigFile: String? = null): Renderer {
fun createRenderer(hub: Hub, applicationName: String, scene: Scene, windowWidth: Int, windowHeight: Int, embedIn: SceneryPanel? = null, embedInDrawable: GLAutoDrawable? = null, renderConfigFile: String? = null): Renderer {
var preference = System.getProperty("scenery.Renderer", null)
val config = renderConfigFile ?: System.getProperty("scenery.Renderer.Config", "DeferredShading.yml")

Expand All @@ -199,7 +200,7 @@ abstract class Renderer : Hubable {
}

return try {
if (preference == "VulkanRenderer") {
if (preference == "VulkanRenderer" && embedInDrawable == null) {
try {
VulkanRenderer(hub, applicationName, scene, windowWidth, windowHeight, embedIn, config)
} catch (e: Exception) {
Expand All @@ -208,14 +209,17 @@ abstract class Renderer : Hubable {
if(logger.isDebugEnabled) {
e.printStackTrace()
}
OpenGLRenderer(hub, applicationName, scene, windowWidth, windowHeight, embedIn, config)
OpenGLRenderer(hub, applicationName, scene, windowWidth, windowHeight, config, embedIn, embedInDrawable)
}
} else {
OpenGLRenderer(hub, applicationName, scene, windowWidth, windowHeight, embedIn, config)
OpenGLRenderer(hub, applicationName, scene, windowWidth, windowHeight, config, embedIn, embedInDrawable)
}
} catch (e: Exception) {
logger.error("Could not instantiate renderer. Is your graphics card working properly and do you have the most recent drivers installed?")
throw RuntimeException("Could not instantiate renderer (${e.cause}, ${e.message})")
if(logger.isDebugEnabled) {
e.printStackTrace()
}
throw e
}
}
}
Expand Down

0 comments on commit fdf1ffd

Please sign in to comment.