From d4be8e8781f753555fe79eb039e1970fa5e2c17b Mon Sep 17 00:00:00 2001 From: edwin Date: Tue, 30 Jul 2019 19:05:23 +0200 Subject: [PATCH] Bump OPENRNDR to 0.3.35-rc1 Bump Kotlin to 1.3.41 Bump kotlinx-coroutines-core to 1.3.0-RC Fix OPENRNDR 0.3.35-rc1 incompatibilities --- build.gradle | 6 +- orx-mesh-generators/src/main/kotlin/Cap.kt | 197 +++++----- .../src/main/kotlin/Cylinder.kt | 163 ++++---- .../src/main/kotlin/GeneratorBuffer.kt | 354 +++++++++--------- orx-olive/build.gradle | 10 +- 5 files changed, 364 insertions(+), 366 deletions(-) diff --git a/build.gradle b/build.gradle index 074be248..a62e819b 100644 --- a/build.gradle +++ b/build.gradle @@ -4,7 +4,7 @@ plugins { allprojects { group 'org.openrndr.extra' - version '0.0.29' + version '0.0.30' } repositories { @@ -13,7 +13,7 @@ repositories { } ext { - openrndrVersion = "0.3.34-rc2" + openrndrVersion = "0.3.35-rc1" } subprojects { @@ -33,7 +33,7 @@ subprojects { compile "org.openrndr:openrndr-core:$openrndrVersion" compile "org.openrndr:openrndr-filter:$openrndrVersion" compile "org.openrndr:openrndr-shape:$openrndrVersion" - compile group: 'org.jetbrains.kotlinx', name: 'kotlinx-coroutines-core', version: '1.0.1' + compile group: 'org.jetbrains.kotlinx', name: 'kotlinx-coroutines-core', version: '1.3.0-RC' } publishing { diff --git a/orx-mesh-generators/src/main/kotlin/Cap.kt b/orx-mesh-generators/src/main/kotlin/Cap.kt index 65f7a116..994d2ccc 100644 --- a/orx-mesh-generators/src/main/kotlin/Cap.kt +++ b/orx-mesh-generators/src/main/kotlin/Cap.kt @@ -1,101 +1,98 @@ -package org.openrndr.extras.meshgenerators - -import org.openrndr.math.Vector2 -import org.openrndr.math.Vector3 -import org.openrndr.math.transforms.rotateY - -fun generateCap(sides: Int, radius: Double, enveloppe: List = listOf(Vector2(0.0, 0.0), Vector2(1.0, 0.0)), writer: VertexWriter) { - val maxX = enveloppe.maxBy { it.x } ?: Vector2(1.0, 0.0) - val a = maxX.x - - val cleanEnveloppe = enveloppe.map { Vector2((it.x / a) * radius, it.y) } - - val normals2D = enveloppe.zipWithNext().map { - val d = it.second - it.first - d.normalized.perpendicular - } - - val basePositions = cleanEnveloppe.map { Vector3(it.x, it.y, 0.0) } - val baseNormals = normals2D.map { Vector3(it.x, it.y, 0.0) } - - for (side in 0 until sides) { - val r0 = rotateY(360.0 / sides * side) - val r1 = rotateY(360.0 / sides * (side + 1)) - - val v0 = basePositions.map { (r0 * it.xyz0).xyz } - val v1 = basePositions.map { (r1 * it.xyz0).xyz } - val n0 = baseNormals.map { (r0 * it.xyz0).xyz } - val n1 = baseNormals.map { (r1 * it.xyz0).xyz } - - for (segment in 0 until basePositions.size - 1) { - - val p00 = v0[segment] - val p01 = v0[segment+1] - val p10 = v1[segment] - val p11 = v1[segment+1] - - val nn0 = n0[segment] - val nn1 = n1[segment] - - writer(p00, nn0, Vector2.ZERO) - writer(p01, nn0, Vector2.ZERO) - writer(p11, nn1, Vector2.ZERO) - - writer(p11, nn1, Vector2.ZERO) - writer(p10, nn1, Vector2.ZERO) - writer(p00, nn0, Vector2.ZERO) - } - } -} - -fun generateRevolve(sides: Int, length: Double, enveloppe: List = listOf(Vector2(1.0, 0.0), Vector2(1.0, 1.0)), writer: VertexWriter) { - val maxY = enveloppe.maxBy { it.y } ?: Vector2(0.0, 1.0) - val a = maxY.y - - val cleanEnveloppe = enveloppe.map { Vector2((it.x), (it.y/a - 0.5) * length ) } - - val normals2D = enveloppe.zipWithNext().map { - val d = it.second - it.first - d.normalized.perpendicular * Vector2(1.0, -1.0) - - } - - val extended = listOf(normals2D[0]) + normals2D + normals2D[normals2D.size-1] - -// extended.zipW - - println(normals2D.joinToString(", ")) - - val basePositions = cleanEnveloppe.map { Vector3(it.x, it.y, 0.0) } - val baseNormals = normals2D.map { Vector3(it.x, it.y, 0.0) } - - for (side in 0 until sides) { - val r0 = rotateY(360.0 / sides * side) - val r1 = rotateY(360.0 / sides * (side + 1)) - - val v0 = basePositions.map { (r0 * it.xyz0).xyz } - val v1 = basePositions.map { (r1 * it.xyz0).xyz } - val n0 = baseNormals.map { (r0 * it.xyz0).xyz } - val n1 = baseNormals.map { (r1 * it.xyz0).xyz } - - for (segment in 0 until basePositions.size - 1) { - - val p00 = v0[segment] - val p01 = v0[segment+1] - val p10 = v1[segment] - val p11 = v1[segment+1] - - val nn0 = n0[segment] - val nn1 = n1[segment] - - writer(p00, nn0, Vector2.ZERO) - writer(p10, nn1, Vector2.ZERO) - writer(p11, nn1, Vector2.ZERO) - - writer(p11, nn1, Vector2.ZERO) - writer(p01, nn0, Vector2.ZERO) - - writer(p00, nn0, Vector2.ZERO) - } - } +package org.openrndr.extras.meshgenerators + +import org.openrndr.math.Matrix44 +import org.openrndr.math.Vector2 +import org.openrndr.math.Vector3 +import org.openrndr.math.transforms.rotateY + +fun generateCap(sides: Int, radius: Double, enveloppe: List = listOf(Vector2(0.0, 0.0), Vector2(1.0, 0.0)), writer: VertexWriter) { + val maxX = enveloppe.maxBy { it.x } ?: Vector2(1.0, 0.0) + val a = maxX.x + + val cleanEnveloppe = enveloppe.map { Vector2((it.x / a) * radius, it.y) } + + val normals2D = enveloppe.zipWithNext().map { + val d = it.second - it.first + d.normalized.perpendicular + } + + val basePositions = cleanEnveloppe.map { Vector3(it.x, it.y, 0.0) } + val baseNormals = normals2D.map { Vector3(it.x, it.y, 0.0) } + + for (side in 0 until sides) { + val r0 = Matrix44.rotateY(360.0 / sides * side) + val r1 = Matrix44.rotateY(360.0 / sides * (side + 1)) + + val v0 = basePositions.map { (r0 * it.xyz0).xyz } + val v1 = basePositions.map { (r1 * it.xyz0).xyz } + val n0 = baseNormals.map { (r0 * it.xyz0).xyz } + val n1 = baseNormals.map { (r1 * it.xyz0).xyz } + + for (segment in 0 until basePositions.size - 1) { + + val p00 = v0[segment] + val p01 = v0[segment+1] + val p10 = v1[segment] + val p11 = v1[segment+1] + + val nn0 = n0[segment] + val nn1 = n1[segment] + + writer(p00, nn0, Vector2.ZERO) + writer(p01, nn0, Vector2.ZERO) + writer(p11, nn1, Vector2.ZERO) + + writer(p11, nn1, Vector2.ZERO) + writer(p10, nn1, Vector2.ZERO) + writer(p00, nn0, Vector2.ZERO) + } + } +} + +fun generateRevolve(sides: Int, length: Double, enveloppe: List = listOf(Vector2(1.0, 0.0), Vector2(1.0, 1.0)), writer: VertexWriter) { + val maxY = enveloppe.maxBy { it.y } ?: Vector2(0.0, 1.0) + val a = maxY.y + + val cleanEnveloppe = enveloppe.map { Vector2((it.x), (it.y/a - 0.5) * length ) } + + val normals2D = enveloppe.zipWithNext().map { + val d = it.second - it.first + d.normalized.perpendicular * Vector2(1.0, -1.0) + + } + + val extended = listOf(normals2D[0]) + normals2D + normals2D[normals2D.size-1] + + val basePositions = cleanEnveloppe.map { Vector3(it.x, it.y, 0.0) } + val baseNormals = normals2D.map { Vector3(it.x, it.y, 0.0) } + + for (side in 0 until sides) { + val r0 = Matrix44.rotateY(360.0 / sides * side) + val r1 = Matrix44.rotateY(360.0 / sides * (side + 1)) + + val v0 = basePositions.map { (r0 * it.xyz0).xyz } + val v1 = basePositions.map { (r1 * it.xyz0).xyz } + val n0 = baseNormals.map { (r0 * it.xyz0).xyz } + val n1 = baseNormals.map { (r1 * it.xyz0).xyz } + + for (segment in 0 until basePositions.size - 1) { + + val p00 = v0[segment] + val p01 = v0[segment+1] + val p10 = v1[segment] + val p11 = v1[segment+1] + + val nn0 = n0[segment] + val nn1 = n1[segment] + + writer(p00, nn0, Vector2.ZERO) + writer(p10, nn1, Vector2.ZERO) + writer(p11, nn1, Vector2.ZERO) + + writer(p11, nn1, Vector2.ZERO) + writer(p01, nn0, Vector2.ZERO) + + writer(p00, nn0, Vector2.ZERO) + } + } } \ No newline at end of file diff --git a/orx-mesh-generators/src/main/kotlin/Cylinder.kt b/orx-mesh-generators/src/main/kotlin/Cylinder.kt index c42bf7d7..d655666e 100644 --- a/orx-mesh-generators/src/main/kotlin/Cylinder.kt +++ b/orx-mesh-generators/src/main/kotlin/Cylinder.kt @@ -1,82 +1,83 @@ -package org.openrndr.extras.meshgenerators - -import org.openrndr.draw.VertexBuffer -import org.openrndr.math.Vector2 -import org.openrndr.math.Vector3 -import org.openrndr.math.mix -import org.openrndr.math.transforms.rotateZ - -fun cylinderMesh(sides: Int = 16, segments: Int = 16, radius: Double = 1.0, length: Double, invert: Boolean = false): VertexBuffer { - val vertexCount = 6 * sides * segments - val vb = meshVertexBuffer(vertexCount) - vb.put { - generateCylinder(sides, segments, radius, length, invert, bufferWriter(this)) - } - return vb -} - -fun generateCylinder(sides: Int, segments: Int, radius: Double, length: Double, invert: Boolean = false, vertexWriter: VertexWriter) { - return generateTaperedCylinder(sides, segments, radius, radius, length, invert, vertexWriter) -} - -fun generateTaperedCylinder(sides: Int, segments: Int, radiusStart: Double, radiusEnd:Double, length: Double, invert: Boolean = false, vertexWriter: VertexWriter) { - val dphi = (Math.PI * 2) / sides - val ddeg = (360.0) / sides - - val invertFactor = if (invert) -1.0 else 1.0 - - val dr = radiusEnd - radiusStart - - val baseNormal = Vector2(length, dr).normalized.perpendicular.let { Vector3(x=it.y, y=0.0, z=it.x)} - //val baseNormal = Vector3(1.0, 0.0, 0.0) - - for (segment in 0 until segments) { - - val radius0 = mix(radiusStart, radiusEnd, segment*1.0/segments) - val radius1 = mix(radiusStart, radiusEnd, (segment+1)*1.0/segments) - val z0 = (length / segments) * segment - length/2.0 - val z1 = (length / segments) * (segment + 1) - length/2.0 - - - for (side in 0 until sides) { - val x00 = Math.cos(side * dphi) * radius0 - val x10 = Math.cos(side * dphi + dphi) * radius0 - val y00 = Math.sin(side * dphi) * radius0 - val y10 = Math.sin(side * dphi + dphi) * radius0 - - val x01 = Math.cos(side * dphi) * radius1 - val x11 = Math.cos(side * dphi + dphi) * radius1 - val y01 = Math.sin(side * dphi) * radius1 - val y11 = Math.sin(side * dphi + dphi) * radius1 - - - val u0 = (segment + 0.0) / segments - val u1 = (segment + 1.0) / segments - val v0 = (side + 0.0) / sides - val v1 = (side + 1.0) / sides - - - val n0 = (rotateZ(side * ddeg) * baseNormal.xyz0).xyz.normalized * invertFactor - val n1 = (rotateZ((side+1) * ddeg) * baseNormal.xyz0).xyz.normalized * invertFactor - - - if (!invert) { - vertexWriter(Vector3(x00, y00, z0), n0, Vector2(u0, v0)) - vertexWriter(Vector3(x10, y10, z0), n1, Vector2(u0, v1)) - vertexWriter(Vector3(x11, y11, z1), n1, Vector2(u1, v1)) - - vertexWriter(Vector3(x11, y11, z1), n1, Vector2(u1, v1)) - vertexWriter(Vector3(x01, y01, z1), n0, Vector2(u1, v0)) - vertexWriter(Vector3(x00, y00, z0), n0, Vector2(u0, v0)) - } else { - vertexWriter(Vector3(x00, y00, z0), n0, Vector2(u0, v0)) - vertexWriter(Vector3(x01, y01, z1), n0, Vector2(u1, v0)) - vertexWriter(Vector3(x11, y11, z1), n1, Vector2(u1, v1)) - - vertexWriter(Vector3(x11, y11, z1), n1, Vector2(u1, v1)) - vertexWriter(Vector3(x10, y10, z0), n1, Vector2(u0, v1)) - vertexWriter(Vector3(x00, y00, z0), n0, Vector2(u0, v0)) - } - } - } +package org.openrndr.extras.meshgenerators + +import org.openrndr.draw.VertexBuffer +import org.openrndr.math.Matrix44 +import org.openrndr.math.Vector2 +import org.openrndr.math.Vector3 +import org.openrndr.math.mix +import org.openrndr.math.transforms.rotateZ + +fun cylinderMesh(sides: Int = 16, segments: Int = 16, radius: Double = 1.0, length: Double, invert: Boolean = false): VertexBuffer { + val vertexCount = 6 * sides * segments + val vb = meshVertexBuffer(vertexCount) + vb.put { + generateCylinder(sides, segments, radius, length, invert, bufferWriter(this)) + } + return vb +} + +fun generateCylinder(sides: Int, segments: Int, radius: Double, length: Double, invert: Boolean = false, vertexWriter: VertexWriter) { + return generateTaperedCylinder(sides, segments, radius, radius, length, invert, vertexWriter) +} + +fun generateTaperedCylinder(sides: Int, segments: Int, radiusStart: Double, radiusEnd:Double, length: Double, invert: Boolean = false, vertexWriter: VertexWriter) { + val dphi = (Math.PI * 2) / sides + val ddeg = (360.0) / sides + + val invertFactor = if (invert) -1.0 else 1.0 + + val dr = radiusEnd - radiusStart + + val baseNormal = Vector2(length, dr).normalized.perpendicular.let { Vector3(x=it.y, y=0.0, z=it.x)} + //val baseNormal = Vector3(1.0, 0.0, 0.0) + + for (segment in 0 until segments) { + + val radius0 = mix(radiusStart, radiusEnd, segment*1.0/segments) + val radius1 = mix(radiusStart, radiusEnd, (segment+1)*1.0/segments) + val z0 = (length / segments) * segment - length/2.0 + val z1 = (length / segments) * (segment + 1) - length/2.0 + + + for (side in 0 until sides) { + val x00 = Math.cos(side * dphi) * radius0 + val x10 = Math.cos(side * dphi + dphi) * radius0 + val y00 = Math.sin(side * dphi) * radius0 + val y10 = Math.sin(side * dphi + dphi) * radius0 + + val x01 = Math.cos(side * dphi) * radius1 + val x11 = Math.cos(side * dphi + dphi) * radius1 + val y01 = Math.sin(side * dphi) * radius1 + val y11 = Math.sin(side * dphi + dphi) * radius1 + + + val u0 = (segment + 0.0) / segments + val u1 = (segment + 1.0) / segments + val v0 = (side + 0.0) / sides + val v1 = (side + 1.0) / sides + + + val n0 = (Matrix44.rotateZ(side * ddeg) * baseNormal.xyz0).xyz.normalized * invertFactor + val n1 = (Matrix44.rotateZ((side+1) * ddeg) * baseNormal.xyz0).xyz.normalized * invertFactor + + + if (!invert) { + vertexWriter(Vector3(x00, y00, z0), n0, Vector2(u0, v0)) + vertexWriter(Vector3(x10, y10, z0), n1, Vector2(u0, v1)) + vertexWriter(Vector3(x11, y11, z1), n1, Vector2(u1, v1)) + + vertexWriter(Vector3(x11, y11, z1), n1, Vector2(u1, v1)) + vertexWriter(Vector3(x01, y01, z1), n0, Vector2(u1, v0)) + vertexWriter(Vector3(x00, y00, z0), n0, Vector2(u0, v0)) + } else { + vertexWriter(Vector3(x00, y00, z0), n0, Vector2(u0, v0)) + vertexWriter(Vector3(x01, y01, z1), n0, Vector2(u1, v0)) + vertexWriter(Vector3(x11, y11, z1), n1, Vector2(u1, v1)) + + vertexWriter(Vector3(x11, y11, z1), n1, Vector2(u1, v1)) + vertexWriter(Vector3(x10, y10, z0), n1, Vector2(u0, v1)) + vertexWriter(Vector3(x00, y00, z0), n0, Vector2(u0, v0)) + } + } + } } \ No newline at end of file diff --git a/orx-mesh-generators/src/main/kotlin/GeneratorBuffer.kt b/orx-mesh-generators/src/main/kotlin/GeneratorBuffer.kt index 125ce779..34077ed6 100644 --- a/orx-mesh-generators/src/main/kotlin/GeneratorBuffer.kt +++ b/orx-mesh-generators/src/main/kotlin/GeneratorBuffer.kt @@ -1,178 +1,178 @@ -package org.openrndr.extras.meshgenerators - -import org.openrndr.draw.VertexBuffer -import org.openrndr.draw.vertexBuffer -import org.openrndr.draw.vertexFormat -import org.openrndr.math.Matrix44 -import org.openrndr.math.Vector2 -import org.openrndr.math.Vector3 -import org.openrndr.math.transforms.rotate -import org.openrndr.math.transforms.transform -import org.openrndr.shape.Shape -import java.nio.ByteBuffer -import java.nio.ByteOrder - -class GeneratorBuffer { - class VertexData(val position: Vector3, val normal: Vector3, val texCoord: Vector2) - - var data = mutableListOf() - - fun write(position: Vector3, normal: Vector3, texCoord: Vector2) { - data.add(VertexData(position, normal, texCoord)) - } - - fun concat(other: GeneratorBuffer) { - data.addAll(other.data) - } - - fun transform(m: Matrix44) { - data = data.map { - VertexData((m * (it.position.xyz1)).xyz, (m * (it.normal.xyz0)).xyz, it.texCoord) - }.toMutableList() - } - - fun toByteBuffer(): ByteBuffer { - val bb = ByteBuffer.allocateDirect(data.size * (3 * 4 + 3 * 4 + 2 * 4)) - bb.order(ByteOrder.nativeOrder()) - bb.rewind() - for (d in data) { - bb.putFloat(d.position.x.toFloat()) - bb.putFloat(d.position.y.toFloat()) - bb.putFloat(d.position.z.toFloat()) - - bb.putFloat(d.normal.x.toFloat()) - bb.putFloat(d.normal.y.toFloat()) - bb.putFloat(d.normal.z.toFloat()) - - bb.putFloat(d.texCoord.x.toFloat()) - bb.putFloat(d.texCoord.y.toFloat()) - } - return bb - } -} - -fun GeneratorBuffer.sphere(sides: Int, segments: Int, radius: Double, invert: Boolean = false) { - generateSphere(sides, segments, radius, invert, this::write) -} - -fun GeneratorBuffer.hemisphere(sides: Int, segments: Int, radius: Double, invert: Boolean = false) { - generateHemisphere(sides, segments, radius, invert, this::write) -} - -enum class GridCoordinates { - INDEX, - UNIPOLAR, - BIPOLAR, -} - -fun GeneratorBuffer.grid(width: Int, height: Int, coordinates: GridCoordinates = GridCoordinates.BIPOLAR, builder: GeneratorBuffer.(u: Double, v: Double) -> Unit) { - for (v in 0 until height) { - for (u in 0 until width) { - group { - when (coordinates) { - GridCoordinates.INDEX -> this.builder(u * 1.0, v * 1.0) - GridCoordinates.BIPOLAR -> this.builder(2 * u / (width - 1.0) - 1, - 2 * v / (height - 1.0) - 1) - GridCoordinates.UNIPOLAR -> this.builder(u / (width - 1.0), v / (height - 1.0)) - } - } - } - } -} - -fun GeneratorBuffer.twist(degreesPerUnit: Double, start: Double, axis: Vector3 = Vector3.UNIT_Y) { - data = data.map { - val p = it.position.projectedOn(axis) - val t = if (axis.x != 0.0) p.x / axis.x else if (axis.y != 0.0) p.y / axis.y else if (axis.z != 0.0) p.z / axis.z else - throw IllegalArgumentException("0 axis") - val r = rotate(axis, t * degreesPerUnit) - GeneratorBuffer.VertexData((r * it.position.xyz1).xyz, (r * it.normal.xyz0).xyz, it.texCoord) - }.toMutableList() -} - -fun GeneratorBuffer.grid(width: Int, height: Int, depth: Int, coordinates: GridCoordinates = GridCoordinates.BIPOLAR, builder: GeneratorBuffer.(u: Double, v: Double, w: Double) -> Unit) { - for (w in 0 until depth) { - for (v in 0 until height) { - for (u in 0 until width) { - group { - when (coordinates) { - GridCoordinates.INDEX -> this.builder(u * 1.0, v * 1.0, w * 1.0) - GridCoordinates.BIPOLAR -> this.builder(2 * u / (width - 1.0) - 1, - 2 * v / (height - 1.0) - 1, 2 * w / (depth - 1.0) - 1) - GridCoordinates.UNIPOLAR -> this.builder(u / (width - 1.0), v / (height - 1.0), w / (depth - 1.0)) - } - } - } - } - } -} - -fun GeneratorBuffer.box(width: Double, height: Double, depth: Double, widthSegments: Int = 1, heightSegments: Int = 1, depthSegments: Int = 1, invert: Boolean = false) { - generateBox(width, height, depth, widthSegments, heightSegments, depthSegments, invert, this::write) -} - -fun GeneratorBuffer.cylinder(sides: Int, segments: Int, radius: Double, length: Double, invert: Boolean = false) { - generateCylinder(sides, segments, radius, length, invert, this::write) -} - -fun GeneratorBuffer.taperedCylinder(sides: Int, segments: Int, startRadius: Double, endRadius: Double, length: Double, invert: Boolean = false) { - generateTaperedCylinder(sides, segments, startRadius, endRadius, length, invert, this::write) -} - -fun GeneratorBuffer.cap(sides: Int, radius: Double, enveloppe: List) { - generateCap(sides, radius, enveloppe, this::write) -} - -fun GeneratorBuffer.revolve(sides:Int, length:Double, enveloppe: List) { - generateRevolve(sides, length, enveloppe, this::write) -} - -fun GeneratorBuffer.extrudeShape(shape: Shape, length: Double, scale: Double = 1.0, distanceTolerance: Double = 0.5) { - extrudeShape(shape, -length / 2.0, length / 2.0, scale, scale, true, true, distanceTolerance, false, this::write) -} - -fun GeneratorBuffer.extrudeShapes(shapes: List, length: Double, scale: Double = 1.0, distanceTolerance: Double = 0.5) { - extrudeShapes(shapes, -length / 2.0, length / 2.0, scale, scale, true, true, distanceTolerance, false, this::write) -} - - - -fun meshGenerator(builder: GeneratorBuffer.() -> Unit): VertexBuffer { - val gb = GeneratorBuffer() - gb.builder() - - val vb = vertexBuffer(vertexFormat { - position(3) - normal(3) - textureCoordinate(2) - }, gb.data.size) - - val bb = gb.toByteBuffer() - bb.rewind() - vb.write(bb) - return vb -} - -fun generator(builder: GeneratorBuffer.() -> Unit): GeneratorBuffer { - val gb = GeneratorBuffer() - gb.builder() - return gb -} - -fun GeneratorBuffer.group(builder: GeneratorBuffer.() -> Unit) { - val gb = GeneratorBuffer() - gb.builder() - this.concat(gb) -} - -fun main(args: Array) { - val gb = generator { - box(20.0, 20.0, 20.0) - group { - box(40.0, 40.0, 40.0) - transform(transform { - translate(0.0, 20.0, 0.0) - }) - } - } +package org.openrndr.extras.meshgenerators + +import org.openrndr.draw.VertexBuffer +import org.openrndr.draw.vertexBuffer +import org.openrndr.draw.vertexFormat +import org.openrndr.math.Matrix44 +import org.openrndr.math.Vector2 +import org.openrndr.math.Vector3 +import org.openrndr.math.transforms.rotate +import org.openrndr.math.transforms.transform +import org.openrndr.shape.Shape +import java.nio.ByteBuffer +import java.nio.ByteOrder + +class GeneratorBuffer { + class VertexData(val position: Vector3, val normal: Vector3, val texCoord: Vector2) + + var data = mutableListOf() + + fun write(position: Vector3, normal: Vector3, texCoord: Vector2) { + data.add(VertexData(position, normal, texCoord)) + } + + fun concat(other: GeneratorBuffer) { + data.addAll(other.data) + } + + fun transform(m: Matrix44) { + data = data.map { + VertexData((m * (it.position.xyz1)).xyz, (m * (it.normal.xyz0)).xyz, it.texCoord) + }.toMutableList() + } + + fun toByteBuffer(): ByteBuffer { + val bb = ByteBuffer.allocateDirect(data.size * (3 * 4 + 3 * 4 + 2 * 4)) + bb.order(ByteOrder.nativeOrder()) + bb.rewind() + for (d in data) { + bb.putFloat(d.position.x.toFloat()) + bb.putFloat(d.position.y.toFloat()) + bb.putFloat(d.position.z.toFloat()) + + bb.putFloat(d.normal.x.toFloat()) + bb.putFloat(d.normal.y.toFloat()) + bb.putFloat(d.normal.z.toFloat()) + + bb.putFloat(d.texCoord.x.toFloat()) + bb.putFloat(d.texCoord.y.toFloat()) + } + return bb + } +} + +fun GeneratorBuffer.sphere(sides: Int, segments: Int, radius: Double, invert: Boolean = false) { + generateSphere(sides, segments, radius, invert, this::write) +} + +fun GeneratorBuffer.hemisphere(sides: Int, segments: Int, radius: Double, invert: Boolean = false) { + generateHemisphere(sides, segments, radius, invert, this::write) +} + +enum class GridCoordinates { + INDEX, + UNIPOLAR, + BIPOLAR, +} + +fun GeneratorBuffer.grid(width: Int, height: Int, coordinates: GridCoordinates = GridCoordinates.BIPOLAR, builder: GeneratorBuffer.(u: Double, v: Double) -> Unit) { + for (v in 0 until height) { + for (u in 0 until width) { + group { + when (coordinates) { + GridCoordinates.INDEX -> this.builder(u * 1.0, v * 1.0) + GridCoordinates.BIPOLAR -> this.builder(2 * u / (width - 1.0) - 1, + 2 * v / (height - 1.0) - 1) + GridCoordinates.UNIPOLAR -> this.builder(u / (width - 1.0), v / (height - 1.0)) + } + } + } + } +} + +fun GeneratorBuffer.twist(degreesPerUnit: Double, start: Double, axis: Vector3 = Vector3.UNIT_Y) { + data = data.map { + val p = it.position.projectedOn(axis) + val t = if (axis.x != 0.0) p.x / axis.x else if (axis.y != 0.0) p.y / axis.y else if (axis.z != 0.0) p.z / axis.z else + throw IllegalArgumentException("0 axis") + val r = Matrix44.rotate(axis, t * degreesPerUnit) + GeneratorBuffer.VertexData((r * it.position.xyz1).xyz, (r * it.normal.xyz0).xyz, it.texCoord) + }.toMutableList() +} + +fun GeneratorBuffer.grid(width: Int, height: Int, depth: Int, coordinates: GridCoordinates = GridCoordinates.BIPOLAR, builder: GeneratorBuffer.(u: Double, v: Double, w: Double) -> Unit) { + for (w in 0 until depth) { + for (v in 0 until height) { + for (u in 0 until width) { + group { + when (coordinates) { + GridCoordinates.INDEX -> this.builder(u * 1.0, v * 1.0, w * 1.0) + GridCoordinates.BIPOLAR -> this.builder(2 * u / (width - 1.0) - 1, + 2 * v / (height - 1.0) - 1, 2 * w / (depth - 1.0) - 1) + GridCoordinates.UNIPOLAR -> this.builder(u / (width - 1.0), v / (height - 1.0), w / (depth - 1.0)) + } + } + } + } + } +} + +fun GeneratorBuffer.box(width: Double, height: Double, depth: Double, widthSegments: Int = 1, heightSegments: Int = 1, depthSegments: Int = 1, invert: Boolean = false) { + generateBox(width, height, depth, widthSegments, heightSegments, depthSegments, invert, this::write) +} + +fun GeneratorBuffer.cylinder(sides: Int, segments: Int, radius: Double, length: Double, invert: Boolean = false) { + generateCylinder(sides, segments, radius, length, invert, this::write) +} + +fun GeneratorBuffer.taperedCylinder(sides: Int, segments: Int, startRadius: Double, endRadius: Double, length: Double, invert: Boolean = false) { + generateTaperedCylinder(sides, segments, startRadius, endRadius, length, invert, this::write) +} + +fun GeneratorBuffer.cap(sides: Int, radius: Double, enveloppe: List) { + generateCap(sides, radius, enveloppe, this::write) +} + +fun GeneratorBuffer.revolve(sides:Int, length:Double, enveloppe: List) { + generateRevolve(sides, length, enveloppe, this::write) +} + +fun GeneratorBuffer.extrudeShape(shape: Shape, length: Double, scale: Double = 1.0, distanceTolerance: Double = 0.5) { + extrudeShape(shape, -length / 2.0, length / 2.0, scale, scale, true, true, distanceTolerance, false, this::write) +} + +fun GeneratorBuffer.extrudeShapes(shapes: List, length: Double, scale: Double = 1.0, distanceTolerance: Double = 0.5) { + extrudeShapes(shapes, -length / 2.0, length / 2.0, scale, scale, true, true, distanceTolerance, false, this::write) +} + + + +fun meshGenerator(builder: GeneratorBuffer.() -> Unit): VertexBuffer { + val gb = GeneratorBuffer() + gb.builder() + + val vb = vertexBuffer(vertexFormat { + position(3) + normal(3) + textureCoordinate(2) + }, gb.data.size) + + val bb = gb.toByteBuffer() + bb.rewind() + vb.write(bb) + return vb +} + +fun generator(builder: GeneratorBuffer.() -> Unit): GeneratorBuffer { + val gb = GeneratorBuffer() + gb.builder() + return gb +} + +fun GeneratorBuffer.group(builder: GeneratorBuffer.() -> Unit) { + val gb = GeneratorBuffer() + gb.builder() + this.concat(gb) +} + +fun main(args: Array) { + val gb = generator { + box(20.0, 20.0, 20.0) + group { + box(40.0, 40.0, 40.0) + transform(transform { + translate(0.0, 20.0, 0.0) + }) + } + } } \ No newline at end of file diff --git a/orx-olive/build.gradle b/orx-olive/build.gradle index 5b08c5d6..1e429855 100644 --- a/orx-olive/build.gradle +++ b/orx-olive/build.gradle @@ -1,8 +1,8 @@ dependencies { compile project(":orx-file-watcher") - compile "org.jetbrains.kotlin:kotlin-scripting-compiler-embeddable:1.3.31" - compile "org.jetbrains.kotlin:kotlin-compiler-embeddable:1.3.31" - compile "org.jetbrains.kotlin:kotlin-script-runtime:1.3.31" - compile "org.jetbrains.kotlin:kotlin-script-util:1.3.31" - compile "org.jetbrains.kotlin:kotlin-scripting-compiler:1.3.31" + compile "org.jetbrains.kotlin:kotlin-scripting-compiler-embeddable:1.3.41" + compile "org.jetbrains.kotlin:kotlin-compiler-embeddable:1.3.41" + compile "org.jetbrains.kotlin:kotlin-script-runtime:1.3.41" + compile "org.jetbrains.kotlin:kotlin-script-util:1.3.41" + compile "org.jetbrains.kotlin:kotlin-scripting-compiler:1.3.41" } \ No newline at end of file