Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/kotlinesque #548

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/main/kotlin/graphics/scenery/Box.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import org.joml.Vector3f
import java.lang.IllegalArgumentException
import kotlin.jvm.JvmOverloads

inline fun Box(sizes: Vector3f = Vector3f(1.0f, 1.0f, 1.0f), insideNormals: Boolean = false, block: Box.() -> Unit): Box = Box(sizes, insideNormals).apply(block)

/**
* Constructs a Box [Node] with the dimensions given in [sizes]
*
Expand Down
2 changes: 2 additions & 0 deletions src/main/kotlin/graphics/scenery/DetachedHeadCamera.kt
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import kotlin.math.PI
import kotlin.math.atan
import kotlin.reflect.KProperty

inline fun DetachedHeadCamera(block: DetachedHeadCamera.() -> Unit): DetachedHeadCamera = DetachedHeadCamera().apply(block)

/**
* Detached Head Camera is a Camera subclass that tracks the head orientation
* in addition to general orientation - useful for HMDs
Expand Down
24 changes: 21 additions & 3 deletions src/main/kotlin/graphics/scenery/Node.kt
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import java.util.concurrent.CopyOnWriteArrayList
import java.util.concurrent.locks.ReentrantLock
import java.util.function.Consumer
import kotlin.collections.ArrayList
import kotlin.collections.Collection

interface Node : Networkable {
var name: String
Expand Down Expand Up @@ -137,6 +138,23 @@ interface Node : Networkable {
/** Unique ID of the Node */
fun getUuid(): UUID

/**
* Attaches a child node to this node.
*
* @param[child] The child to attach to this node.
*/
operator fun plusAssign(child: Node) = addChild(child)

/**
* Attaches the given children nodes to this node.
*
* @param[children] The children to attach to this node.
*/
operator fun plusAssign(children: Collection<Node>) {
for (child in children)
addChild(child)
}

/**
* Attaches a child node to this node.
*
Expand Down Expand Up @@ -185,12 +203,12 @@ interface Node : Networkable {
*/
fun generateBoundingBox(): OrientedBoundingBox? {
val geometry = geometryOrNull()
if(geometry == null) {
return if(geometry == null) {
logger.warn("$name: Assuming 3rd party BB generation")
return boundingBox
boundingBox
} else {
boundingBox = geometry.generateBoundingBox(children)
return boundingBox
boundingBox
}
}

Expand Down
2 changes: 2 additions & 0 deletions src/main/kotlin/graphics/scenery/PointLight.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import graphics.scenery.utils.extensions.xyz
import org.joml.Vector3f
import org.joml.Vector4f

inline fun PointLight(radius: Float = 5.0f, block: PointLight.() -> Unit): PointLight = PointLight(radius).apply(block)

/**
* Point light class.
*
Expand Down
7 changes: 7 additions & 0 deletions src/main/kotlin/graphics/scenery/utils.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package graphics.scenery

inline operator fun <M : Mesh> M.invoke(init: M.() -> Unit): M {
apply(init)
return this
}

22 changes: 22 additions & 0 deletions src/main/kotlin/graphics/scenery/utils/Image.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package graphics.scenery.utils

import graphics.scenery.textures.Texture
import graphics.scenery.volumes.Colormap
import net.imglib2.type.numeric.integer.UnsignedByteType
import org.joml.Vector3i
import org.lwjgl.system.MemoryUtil
import java.awt.Color
import java.awt.color.ColorSpace
Expand All @@ -22,6 +25,17 @@ import javax.imageio.ImageIO
*/
open class Image(val contents: ByteBuffer, val width: Int, val height: Int, val depth: Int = 1) {

fun toTexture(
repeatUVW: Triple<Texture.RepeatMode, Texture.RepeatMode, Texture.RepeatMode> = Texture.RepeatMode.Repeat.all(),
borderColor: Texture.BorderColor = Texture.BorderColor.OpaqueBlack,
normalized: Boolean = true,
mipmap: Boolean = true,
minFilter: Texture.FilteringMode = Texture.FilteringMode.Linear,
maxFilter: Texture.FilteringMode = Texture.FilteringMode.Linear,
usage: HashSet<Texture.UsageType> = hashSetOf(Texture.UsageType.Texture)
): Texture {
return Texture(Vector3i(width, height, depth),4, UnsignedByteType(), contents, repeatUVW, borderColor, normalized, mipmap, usageType = usage, minFilter = minFilter, maxFilter = maxFilter)
}
companion object {
protected val logger by lazyLogger()

Expand Down Expand Up @@ -98,6 +112,14 @@ open class Image(val contents: ByteBuffer, val width: Int, val height: Int, val
return Image(imageData, bi.width, bi.height)
}

/**
* Creates an Image from a resource given in [path], with [baseClass] as basis for the search path.
* [path] is expected to end in an extension (e.g., ".png"), such that the file type can be determined.
*/
inline fun <reified K> fromResource(path: String): Image {
return fromStream(K::class.java.getResourceAsStream(path), path.substringAfterLast(".").lowercase())
}

/**
* Creates an Image from a resource given in [path], with [baseClass] as basis for the search path.
* [path] is expected to end in an extension (e.g., ".png"), such that the file type can be determined.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,60 +19,56 @@ class ArcballExample : SceneryBase("ArcballExample") {
override fun init() {
renderer = hub.add(Renderer.createRenderer(hub, applicationName, scene, 1024, 1024))

val cam: Camera = DetachedHeadCamera()
with(cam) {
val cam: Camera = DetachedHeadCamera {
spatial {
position = Vector3f(0.0f, 0.0f, 2.5f)
}
perspectiveCamera(70.0f, windowWidth, windowHeight)

targeted = true
target = Vector3f(0.0f, 0.0f, 0.0f)

scene.addChild(this)
}
scene += cam

val camlight = PointLight(3.0f)
camlight.intensity = 5.0f
cam.addChild(camlight)

val box = Box(Vector3f(1.0f, 1.0f, 1.0f))
val camlight = PointLight(3.0f) {
intensity = 5.0f
}
cam += camlight
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a neat trick. But I find it odd to override plusAssign but not plus. The implication, which is not true for these types, is that cam + camlight would be a new camera object with the light added, and only because the += was used does it get assigned back into the same cam variable. Is this a pattern Kotlin users often use for mutators, to override only the += but not +?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Huh, I guess it's convenient, so I'll swallow my feelings of mathematical discomfort 😆

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We might say this is one of the example on the border line, some people will assume this to be an operator abuse, others don't

But that's where I like to give the choice :)


with(box) {
val box = Box(Vector3f(1.0f, 1.0f, 1.0f)) {
spatial {
position = Vector3f(0.0f, 0.0f, 0.0f)
}
material {
ambient = Vector3f(1.0f, 0.0f, 0.0f)
diffuse = Vector3f(0.0f, 1.0f, 0.0f)
textures["diffuse"] = Texture.fromImage(Image.fromResource("textures/helix.png", TexturedCubeExample::class.java))
textures["diffuse"] = Image.fromResource<TexturedCubeExample>("textures/helix.png").toTexture()
specular = Vector3f(1.0f, 1.0f, 1.0f)
}

scene.addChild(this)
}
scene += box

val lights = (0..2).map {
PointLight(radius = 15.0f)
}.map { light ->
light.spatial {
position = Random.random3DVectorFromRange(-3.0f, 3.0f)
val lights = List(3) {
PointLight(radius = 15.0f) {
spatial {
position = Random.random3DVectorFromRange(-3.0f, 3.0f)
}
emissionColor = Random.random3DVectorFromRange(0.2f, 0.8f)
intensity = Random.randomFromRange(0.1f, 0.8f)
}
light.emissionColor = Random.random3DVectorFromRange(0.2f, 0.8f)
light.intensity = Random.randomFromRange(0.1f, 0.8f)
light
}

val floor = Box(Vector3f(500.0f, 0.05f, 500.0f))
floor.spatial {
position = Vector3f(0.0f, -1.0f, 0.0f)
}
floor.material {
diffuse = Vector3f(1.0f, 1.0f, 1.0f)
val floor = Box(Vector3f(500.0f, 0.05f, 500.0f)) {
spatial {
position = Vector3f(0.0f, -1.0f, 0.0f)
}
material {
diffuse = Vector3f(1.0f, 1.0f, 1.0f)
}
}
scene.addChild(floor)
scene += floor

lights.forEach(scene::addChild)
scene += lights
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Assuming the += trick is deemed kosher by @skalarproduktraum, the fact that you can += a whole list of children at once is very cool!

}

override fun inputSetup() {
Expand Down