-
Notifications
You must be signed in to change notification settings - Fork 33
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
Small kool showcase examples #532
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,10 +1,19 @@ | ||
package graphics.scenery | ||
|
||
import graphics.scenery.utils.Face | ||
import graphics.scenery.utils.extensions.minus | ||
import graphics.scenery.utils.extensions.plus | ||
import graphics.scenery.utils.extensions.times | ||
import graphics.scenery.utils.extensions.xy | ||
import graphics.scenery.utils.inc | ||
import graphics.scenery.utils.set | ||
import kool.FloatBuffer | ||
import kool.IntBuffer | ||
import kool.adr | ||
import kool.toPtr | ||
import org.joml.Vector2f | ||
import org.joml.Vector3f | ||
import org.lwjgl.system.MemoryUtil | ||
import java.util.* | ||
import kotlin.math.* | ||
|
||
|
@@ -16,15 +25,15 @@ import kotlin.math.* | |
* @param[subdivisions] Number of subdivisions of the base icosahedron | ||
*/ | ||
open class Icosphere(val radius: Float, val subdivisions: Int) : Mesh("Icosphere") { | ||
fun MutableList<Vector3f>.addVertex(vararg v: Float) { | ||
this.add(Vector3f(v)) | ||
fun MutableList<Vector3f>.addVertex(x: Float, y: Float, z: Float) { | ||
this += Vector3f(x, y, z) | ||
} | ||
|
||
fun MutableList<Triple<Int, Int, Int>>.addFace(i: Int, j: Int, k: Int) { | ||
this.add(kotlin.Triple(i, j, k)) | ||
fun MutableList<Face>.addFace(i: Int, j: Int, k: Int) { | ||
this += Triple(i, j, k) | ||
} | ||
|
||
protected fun createBaseVertices(vertices: MutableList<Vector3f>, indices: MutableList<Triple<Int, Int, Int>>) { | ||
protected fun createBaseVertices(vertices: MutableList<Vector3f>, indices: MutableList<Face>) { | ||
val s = sqrt((5.0f - sqrt(5.0f)) / 10.0f) | ||
val t = sqrt((5.0f + sqrt(5.0f)) / 10.0f) | ||
|
||
|
@@ -73,11 +82,11 @@ open class Icosphere(val radius: Float, val subdivisions: Int) : Mesh("Icosphere | |
|
||
protected fun refineTriangles(recursionLevel: Int, | ||
vertices: MutableList<Vector3f>, | ||
indices: MutableList<Triple<Int, Int, Int>>): MutableList<Triple<Int, Int, Int>> { | ||
indices: MutableList<Face>): MutableList<Face> { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hooray for type aliasing! 🏆 |
||
// refine triangles | ||
var faces = indices | ||
(0 until recursionLevel).forEach { | ||
val faces2 = ArrayList<Triple<Int, Int, Int>>(indices.size * 3) | ||
repeat(recursionLevel) { | ||
val faces2 = ArrayList<Face>(indices.size * 3) | ||
|
||
for (triangle in faces) { | ||
// replace triangle by 4 triangles | ||
|
@@ -124,7 +133,7 @@ open class Icosphere(val radius: Float, val subdivisions: Int) : Mesh("Icosphere | |
val i = this.addVertex(middle) | ||
|
||
// store it, return index | ||
middlePointIndexCache.put(key, i) | ||
middlePointIndexCache[key] = i | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @elect86 Do you notice these manually, or lean on an IDE cleanup/simplification action? If so, what is it? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If suggested, "Alt+Enter" opens the action dialog and then you select the suggestion Otherwise you need to explicitely call |
||
return i | ||
} | ||
|
||
|
@@ -136,17 +145,20 @@ open class Icosphere(val radius: Float, val subdivisions: Int) : Mesh("Icosphere | |
|
||
init { | ||
val vertexBuffer = ArrayList<Vector3f>() | ||
val indexBuffer = ArrayList<Triple<Int, Int, Int>>() | ||
val indexBuffer = ArrayList<Face>() | ||
|
||
createBaseVertices(vertexBuffer, indexBuffer) | ||
val faces = refineTriangles(subdivisions, vertexBuffer, indexBuffer) | ||
|
||
geometry { | ||
|
||
vertices = BufferUtils.allocateFloat(faces.size * 3 * 3) | ||
normals = BufferUtils.allocateFloat(faces.size * 3 * 3) | ||
texcoords = BufferUtils.allocateFloat(faces.size * 3 * 2) | ||
indices = BufferUtils.allocateInt(0) | ||
vertices = FloatBuffer(faces.size * 3 * 3) | ||
normals = FloatBuffer(faces.size * 3 * 3) | ||
texcoords = FloatBuffer(faces.size * 3 * 2) | ||
indices = IntBuffer(0) | ||
var pVtx = vertices.adr.toPtr<Vector3f>() | ||
var pNorm = normals.adr.toPtr<Vector3f>() | ||
var pTxc = texcoords.adr.toPtr<Vector2f>() | ||
|
||
faces.forEach { f -> | ||
val v1 = vertexBuffer[f.first] | ||
|
@@ -156,13 +168,13 @@ open class Icosphere(val radius: Float, val subdivisions: Int) : Mesh("Icosphere | |
val uv2 = vertexToUV(v2.normalize()) | ||
val uv3 = vertexToUV(v3.normalize()) | ||
|
||
(v1 * radius).get(vertices).position(vertices.position() + 3) | ||
(v2 * radius).get(vertices).position(vertices.position() + 3) | ||
(v3 * radius).get(vertices).position(vertices.position() + 3) | ||
pVtx++[0] = v1 * radius | ||
pVtx++[0] = v2 * radius | ||
pVtx++[0] = v3 * radius | ||
|
||
v1.get(normals).position(normals.position() + 3) | ||
v2.get(normals).position(normals.position() + 3) | ||
v3.get(normals).position(normals.position() + 3) | ||
pNorm++[0] = v1 | ||
pNorm++[0] = v2 | ||
pNorm++[0] = v3 | ||
|
||
val uvNormal = (uv2 - uv1).cross(uv3 - uv1) | ||
if(uvNormal.z() < 0.0f) { | ||
|
@@ -177,14 +189,10 @@ open class Icosphere(val radius: Float, val subdivisions: Int) : Mesh("Icosphere | |
} | ||
} | ||
|
||
uv1.xy().get(texcoords).position(texcoords.position() + 2) | ||
uv2.xy().get(texcoords).position(texcoords.position() + 2) | ||
uv3.xy().get(texcoords).position(texcoords.position() + 2) | ||
pTxc++[0] = uv1.xy() | ||
pTxc++[0] = uv2.xy() | ||
pTxc++[0] = uv3.xy() | ||
} | ||
|
||
vertices.flip() | ||
normals.flip() | ||
texcoords.flip() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just to be sure: the kool There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm using absolute methods to upload data, that's why There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Cool, I just wanted to make sure these lines didn't get dropped by accident. 👍 |
||
} | ||
|
||
boundingBox = generateBoundingBox() | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,6 +3,10 @@ package graphics.scenery.attribute.geometry | |
import graphics.scenery.* | ||
import graphics.scenery.geometry.GeometryType | ||
import graphics.scenery.utils.extensions.minus | ||
import graphics.scenery.utils.get | ||
import graphics.scenery.utils.inc | ||
import graphics.scenery.utils.set | ||
import kool.* | ||
import org.joml.Vector3f | ||
import java.io.Serializable | ||
import java.nio.FloatBuffer | ||
|
@@ -41,38 +45,22 @@ interface Geometry : Serializable { | |
* STL's facet storage format into account. | ||
*/ | ||
fun recalculateNormals() { | ||
val vertexBufferView = vertices.asReadOnlyBuffer() | ||
var i = 0 | ||
val normals = ArrayList<Float>() | ||
var pVtx = vertices.adr.toPtr<Vector3f>() | ||
var pNorm = normals.adr.toPtr<Vector3f>() | ||
|
||
while (i < vertexBufferView.limit() - 1) { | ||
val v1 = Vector3f(vertexBufferView[i], vertexBufferView[i + 1], vertexBufferView[i + 2]) | ||
i += 3 | ||
|
||
val v2 = Vector3f(vertexBufferView[i], vertexBufferView[i + 1], vertexBufferView[i + 2]) | ||
i += 3 | ||
|
||
val v3 = Vector3f(vertexBufferView[i], vertexBufferView[i + 1], vertexBufferView[i + 2]) | ||
i += 3 | ||
for (i in vertices.indices step 3) { | ||
val v1 = pVtx++[0] | ||
val v2 = pVtx++[0] | ||
val v3 = pVtx++[0] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is super concise, but I find it harder to understand. Maybe a middle ground could be: fun makeVector(array, i) { return Vector3f(array[i], array[i + 1], array[i + 2]) }
val v1 = makeVector(vertexBufferView, i += 3)
val v2 = makeVector(vertexBufferView, i += 3)
val v3 = makeVector(vertexBufferView, i += 3) or some such? Or even attach a It is fun to use overloaded operators, but the pointer thing with There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. it's essentially Another alternative:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nice, I like that much more! |
||
|
||
val a = v2 - v1 | ||
val b = v3 - v1 | ||
|
||
val n = a.cross(b).normalize() | ||
|
||
normals.add(n.x()) | ||
normals.add(n.y()) | ||
normals.add(n.z()) | ||
|
||
normals.add(n.x()) | ||
normals.add(n.y()) | ||
normals.add(n.z()) | ||
|
||
normals.add(n.x()) | ||
normals.add(n.y()) | ||
normals.add(n.z()) | ||
pNorm++[0] = n | ||
pNorm++[0] = n | ||
pNorm++[0] = n | ||
} | ||
|
||
this.normals = BufferUtils.allocateFloatAndPut(normals.toFloatArray()) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
package graphics.scenery.utils | ||
|
||
typealias Face = Triple<Int, Int, Int> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
package graphics.scenery.utils | ||
|
||
import kool.Ptr | ||
import kool.unsafe | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ❗ unsafe? Like There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yep, atm it's the way for low level native operations The whole Lwjgl ultimately rely on that as well |
||
import org.joml.Vector2f | ||
import org.joml.Vector3f | ||
|
||
@JvmName("Vector3fGet") | ||
operator fun Ptr<Vector3f>.get(index: Int): Vector3f { | ||
val ofs = adr.toLong() + (index shl 2) | ||
return Vector3f(unsafe.getFloat(ofs), unsafe.getFloat(ofs + 4), unsafe.getFloat(ofs + 8)) | ||
} | ||
|
||
@JvmName("Vector3fSet") | ||
operator fun Ptr<Vector3f>.set(index: Int, v: Vector3f) { | ||
val ofs = adr.toLong() + (index shl 2) | ||
unsafe.putFloat(ofs, v.x) | ||
unsafe.putFloat(ofs + 4, v.y) | ||
unsafe.putFloat(ofs + 8, v.z) | ||
} | ||
@JvmName("Vector2fSet") | ||
operator fun Ptr<Vector2f>.set(index: Int, v: Vector2f) { | ||
val ofs = adr.toLong() + (index shl 2) | ||
unsafe.putFloat(ofs, v.x) | ||
unsafe.putFloat(ofs + 4, v.y) | ||
} | ||
|
||
@JvmName("Vector3fInc") | ||
operator fun Ptr<Vector3f>.inc() = Ptr<Vector3f>(adr.toLong() + 12) | ||
@JvmName("Vector2fInc") | ||
operator fun Ptr<Vector2f>.inc() = Ptr<Vector2f>(adr.toLong() + 8) |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -11,6 +11,7 @@ import graphics.scenery.volumes.Volume | |
import graphics.scenery.volumes.VolumeManager | ||
import ij.IJ | ||
import ij.ImagePlus | ||
import kool.ByteBuffer | ||
import net.imglib2.img.Img | ||
import net.imglib2.img.display.imagej.ImageJFunctions | ||
import net.imglib2.type.numeric.integer.UnsignedShortType | ||
|
@@ -40,7 +41,7 @@ class CustomVolumeManagerExample : SceneryBase("CustomVolumeManagerExample") { | |
)) | ||
volumeManager.customTextures.add("OutputRender") | ||
|
||
val outputBuffer = MemoryUtil.memCalloc(1280*720*4) | ||
val outputBuffer = ByteBuffer(1280*720*4) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I love the conciseness of this. But it makes me nervous that the kool buffer types are named There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. They look like types, but are methods instead. It's a technique called fake/dummy constructors. You'll recognize those in the IDE by being in italics It's coherent with the current way to allocate Arrays and Lists
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nice. As long as they are actually returning |
||
val outputTexture = Texture.fromImage(Image(outputBuffer, 1280, 720), usage = hashSetOf(Texture.UsageType.LoadStoreImage, Texture.UsageType.Texture)) | ||
volumeManager.material().textures["OutputRender"] = outputTexture | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we please get artifacts deployed to maven.scijava.org, instead of a custom GitHub-based repository, which should not be done?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What shouldn't be done is loading big jars (ie fat jars)
This is not the case, the ones I push weight few KBs
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It shouldn't be done at all IMHO—now you have to run that repo forever or else old builds will break. And as described in that article, it creates a situation where there's another repository that has to be queried for all the dependencies, slowing down builds. Just release the projects on maven.scijava.org or oss.sonatype.org! Once you have the infrastructure in place for Sonatype, deploying is a button push—the only huge PITA is getting it set up at the beginning.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
True, but you know what I have to do to run it forever? Just avoid deleting it
I might be move everything to maven, though (here)
I'd love to deploy to maven.scijava.org, but I have a dev way to release very often and that wasn't compatible with that, or do I recall it wrong?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Publishing to maven.scijava.org is just a standard deploy over WebDAV, I'm sure the Gradle tooling will support it with your credentials both manually and/or automatically. As long as your tooling doesn't try to deploy the same release artifact more than once, which is forbidden due to release artifacts being immutable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How much does it take the publication over there? How long before it's available for consumption?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Artifacts published to maven.scijava.org are available instantly. Artifacts published to oss.sonatype.org (or s01.oss.sonatype.org) are available instantly from those URLs, but typically take 10-30 minutes to get mirrored over to Maven Central.