[orx-mesh, orx-obj-loader] Separate into commonMain and jvmMain
This commit is contained in:
@@ -1,5 +1,8 @@
|
||||
package org.openrndr.extra.objloader
|
||||
|
||||
/**
|
||||
* Compound mesh data interface
|
||||
*/
|
||||
interface ICompoundMeshData {
|
||||
val vertexData: IVertexData
|
||||
val compounds: Map<String, IMeshData>
|
||||
@@ -12,6 +15,10 @@ class CompoundMeshData(
|
||||
override val compounds: Map<String, MeshData>
|
||||
) : ICompoundMeshData {
|
||||
|
||||
init {
|
||||
|
||||
}
|
||||
|
||||
override fun triangulate(): CompoundMeshData {
|
||||
return CompoundMeshData(vertexData, compounds.mapValues {
|
||||
it.value.triangulate()
|
||||
@@ -25,6 +32,10 @@ class MutableCompoundMeshData(
|
||||
) : ICompoundMeshData {
|
||||
|
||||
override fun triangulate(): MutableCompoundMeshData {
|
||||
TODO("Not yet implemented")
|
||||
return MutableCompoundMeshData(
|
||||
vertexData,
|
||||
compounds.mapValues {
|
||||
it.value.triangulate()
|
||||
}.toMutableMap())
|
||||
}
|
||||
}
|
||||
@@ -19,6 +19,6 @@ fun ICompoundMeshData.toVertexBuffer(): VertexBuffer {
|
||||
return vertexBuffer
|
||||
}
|
||||
|
||||
fun ICompoundMeshData.flattenPolygons(): Map<String, List<IPolygon>> {
|
||||
return compounds.mapValues { it.value.flattenPolygons() }
|
||||
fun ICompoundMeshData.toPolygons(): Map<String, List<IPolygon>> {
|
||||
return compounds.mapValues { it.value.toPolygons() }
|
||||
}
|
||||
@@ -9,12 +9,38 @@ import kotlin.math.abs
|
||||
import kotlin.math.atan2
|
||||
import kotlin.math.round
|
||||
|
||||
/**
|
||||
* Indexed polygon interface
|
||||
*/
|
||||
interface IIndexedPolygon {
|
||||
/**
|
||||
* Position indices
|
||||
*/
|
||||
val positions: List<Int>
|
||||
|
||||
/**
|
||||
* Texture coordinate indices, optional
|
||||
*/
|
||||
val textureCoords: List<Int>
|
||||
|
||||
/**
|
||||
* Normal indices, optional
|
||||
*/
|
||||
val normals: List<Int>
|
||||
|
||||
/**
|
||||
* Color indices, optional
|
||||
*/
|
||||
val colors: List<Int>
|
||||
|
||||
/**
|
||||
* Tangents, optional
|
||||
*/
|
||||
val tangents: List<Int>
|
||||
|
||||
/**
|
||||
* Bitangents, optional
|
||||
*/
|
||||
val bitangents: List<Int>
|
||||
|
||||
fun base(vertexData: IVertexData): Matrix44 {
|
||||
@@ -30,6 +56,11 @@ interface IIndexedPolygon {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if polygon is planar
|
||||
* @param vertexData the vertex data
|
||||
* @param eps error tolerance
|
||||
*/
|
||||
fun isPlanar(vertexData: IVertexData, eps: Double = 1E-2): Boolean {
|
||||
fun normal(i: Int): Vector3 {
|
||||
val p0 = vertexData.positions[positions[(i - 1).mod(positions.size)]]
|
||||
@@ -48,6 +79,9 @@ interface IIndexedPolygon {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine polygon convexity
|
||||
*/
|
||||
fun isConvex(vertexData: IVertexData): Boolean {
|
||||
val planar = base(vertexData).inversed
|
||||
|
||||
@@ -99,10 +133,16 @@ interface IIndexedPolygon {
|
||||
return abs(round(angleSum / (2 * PI))) == 1.0
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert to [IPolygon]
|
||||
* @param vertexData the vertex data required to build the [IPolygon]
|
||||
*/
|
||||
fun toPolygon(vertexData: IVertexData): IPolygon
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Immutable indexed polygon implementation
|
||||
*/
|
||||
data class IndexedPolygon(
|
||||
override val positions: List<Int>,
|
||||
override val textureCoords: List<Int>,
|
||||
@@ -113,7 +153,7 @@ data class IndexedPolygon(
|
||||
|
||||
) : IIndexedPolygon {
|
||||
|
||||
fun tessellate(vertexData: IVertexData): List<IndexedPolygon> {
|
||||
private fun tessellate(vertexData: IVertexData): List<IndexedPolygon> {
|
||||
val points = vertexData.positions.slice(positions.toList())
|
||||
val triangles = org.openrndr.shape.triangulate(listOf(points))
|
||||
|
||||
@@ -129,6 +169,11 @@ data class IndexedPolygon(
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert to a list of triangle [IndexedPolygon]
|
||||
*
|
||||
* Supports non-planar and non-convex polygons
|
||||
*/
|
||||
fun triangulate(vertexData: IVertexData): List<IndexedPolygon> {
|
||||
return when {
|
||||
positions.size == 3 -> listOf(this)
|
||||
@@ -180,6 +225,9 @@ data class IndexedPolygon(
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Mutable indexed polygon implementation
|
||||
*/
|
||||
data class MutableIndexedPolygon(
|
||||
override val positions: MutableList<Int>,
|
||||
override val textureCoords: MutableList<Int>,
|
||||
|
||||
@@ -2,13 +2,19 @@ package org.openrndr.extra.objloader
|
||||
|
||||
import kotlin.jvm.JvmRecord
|
||||
|
||||
/**
|
||||
* Mesh data interface
|
||||
*/
|
||||
interface IMeshData {
|
||||
val vertexData: IVertexData
|
||||
val polygons: List<IIndexedPolygon>
|
||||
fun triangulate(): IMeshData
|
||||
fun flattenPolygons(): List<IPolygon>
|
||||
fun toPolygons(): List<IPolygon>
|
||||
}
|
||||
|
||||
/**
|
||||
* Immutable mesh data implementation
|
||||
*/
|
||||
@JvmRecord
|
||||
data class MeshData(
|
||||
override val vertexData: VertexData,
|
||||
@@ -18,7 +24,7 @@ data class MeshData(
|
||||
return copy(polygons = polygons.flatMap { polygon -> polygon.triangulate(vertexData) })
|
||||
}
|
||||
|
||||
override fun flattenPolygons(): List<Polygon> {
|
||||
override fun toPolygons(): List<Polygon> {
|
||||
return polygons.map { ip ->
|
||||
ip.toPolygon(vertexData)
|
||||
}
|
||||
@@ -26,6 +32,9 @@ data class MeshData(
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Mutable mesh data implementation
|
||||
*/
|
||||
data class MutableMeshData(
|
||||
override val vertexData: MutableVertexData,
|
||||
override val polygons: MutableList<IndexedPolygon>
|
||||
@@ -34,8 +43,7 @@ data class MutableMeshData(
|
||||
return copy(polygons = polygons.flatMap { it.triangulate(vertexData) }.toMutableList())
|
||||
}
|
||||
|
||||
override fun flattenPolygons(): List<Polygon> {
|
||||
override fun toPolygons(): List<Polygon> {
|
||||
return polygons.map { it.toPolygon(vertexData) }
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
package org.openrndr.extra.objloader
|
||||
|
||||
import org.openrndr.color.ColorRGBa
|
||||
import org.openrndr.draw.VertexBuffer
|
||||
import org.openrndr.draw.VertexFormat
|
||||
import org.openrndr.draw.vertexBuffer
|
||||
@@ -13,13 +14,14 @@ internal val objVertexFormat = vertexFormat {
|
||||
position(3)
|
||||
normal(3)
|
||||
textureCoordinate(2)
|
||||
color(4)
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a [MeshData] instance into a [VertexBuffer]
|
||||
*/
|
||||
fun IMeshData.toVertexBuffer(elementOffset: Int = 0, vertexBuffer: VertexBuffer? = null): VertexBuffer {
|
||||
val objects = triangulate().flattenPolygons()
|
||||
val objects = triangulate().toPolygons()
|
||||
val triangleCount = objects.size
|
||||
val vertexBuffer = vertexBuffer ?: vertexBuffer(objVertexFormat, triangleCount * 3)
|
||||
|
||||
@@ -40,11 +42,14 @@ fun IMeshData.toVertexBuffer(elementOffset: Int = 0, vertexBuffer: VertexBuffer?
|
||||
} else {
|
||||
write(Vector2.ZERO)
|
||||
}
|
||||
if (it.colors.isNotEmpty()) {
|
||||
write(it.colors[i])
|
||||
} else {
|
||||
write(ColorRGBa.WHITE)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
vertexBuffer.shadow.destroy()
|
||||
return vertexBuffer
|
||||
}
|
||||
@@ -8,6 +8,10 @@ import org.openrndr.shape.Box
|
||||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
|
||||
|
||||
/**
|
||||
* 3D Polygon interface
|
||||
*/
|
||||
interface IPolygon {
|
||||
val positions: List<Vector3>
|
||||
val normals: List<Vector3>
|
||||
@@ -20,7 +24,7 @@ interface IPolygon {
|
||||
}
|
||||
|
||||
/**
|
||||
* A 3D Polygon
|
||||
* Immutable 3D Polygon implementation
|
||||
*
|
||||
* @property positions Vertex 3D positions
|
||||
* @property normals Vertex 3D normals
|
||||
@@ -54,6 +58,9 @@ class Polygon(
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Mutable 3D Polygon implementation
|
||||
*/
|
||||
class MutablePolygon(
|
||||
override val positions: MutableList<Vector3> = mutableListOf(),
|
||||
override val normals: MutableList<Vector3> = mutableListOf(),
|
||||
@@ -77,7 +84,7 @@ class MutablePolygon(
|
||||
|
||||
|
||||
/**
|
||||
* Calculates the 3D bounding box of a list of [IPolygon].
|
||||
* Calculate the 3D bounding box of a list of [IPolygon].
|
||||
*/
|
||||
fun bounds(polygons: List<IPolygon>): Box {
|
||||
var minX = Double.POSITIVE_INFINITY
|
||||
@@ -101,3 +108,42 @@ fun bounds(polygons: List<IPolygon>): Box {
|
||||
}
|
||||
return Box(Vector3(minX, minY, minZ), maxX - minX, maxY - minY, maxZ - minZ)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Convert list of polygons to [MeshData]
|
||||
*/
|
||||
fun List<IPolygon>.toMeshData(): MeshData {
|
||||
val vertexData = MutableVertexData()
|
||||
|
||||
for (p in this) {
|
||||
vertexData.positions.addAll(p.positions)
|
||||
vertexData.normals.addAll(p.normals)
|
||||
vertexData.colors.addAll(p.colors)
|
||||
vertexData.textureCoords.addAll(p.textureCoords)
|
||||
vertexData.tangents.addAll(p.tangents)
|
||||
vertexData.bitangents.addAll(p.bitangents)
|
||||
}
|
||||
|
||||
val indexedPolygons = mutableListOf<IndexedPolygon>()
|
||||
|
||||
var vertexOffset = 0
|
||||
for (p in this) {
|
||||
|
||||
val indices = (vertexOffset until vertexOffset + p.positions.size).toList()
|
||||
|
||||
indexedPolygons.add(
|
||||
IndexedPolygon(
|
||||
positions = indices,
|
||||
textureCoords = if (p.textureCoords.isNotEmpty()) indices else emptyList(),
|
||||
normals = if (p.normals.isNotEmpty()) indices else emptyList(),
|
||||
colors = if (p.colors.isNotEmpty()) indices else emptyList(),
|
||||
tangents = if (p.tangents.isNotEmpty()) indices else emptyList(),
|
||||
bitangents = if (p.bitangents.isNotEmpty()) indices else emptyList()
|
||||
)
|
||||
)
|
||||
|
||||
vertexOffset += p.positions.size
|
||||
}
|
||||
return MeshData(vertexData.toVertexData(), indexedPolygons)
|
||||
}
|
||||
@@ -4,7 +4,6 @@ import org.openrndr.color.ColorRGBa
|
||||
import org.openrndr.math.Vector2
|
||||
import org.openrndr.math.Vector3
|
||||
|
||||
|
||||
/**
|
||||
* Vertex data interface
|
||||
*/
|
||||
@@ -40,6 +39,9 @@ interface IVertexData {
|
||||
val bitangents: List<Vector3>
|
||||
}
|
||||
|
||||
/**
|
||||
* Immutable vertex data implementation
|
||||
*/
|
||||
class VertexData(
|
||||
override val positions: List<Vector3> = emptyList(),
|
||||
override val normals: List<Vector3> = emptyList(),
|
||||
@@ -47,8 +49,27 @@ class VertexData(
|
||||
override val colors: List<ColorRGBa> = emptyList(),
|
||||
override val tangents: List<Vector3> = emptyList(),
|
||||
override val bitangents: List<Vector3> = emptyList()
|
||||
) : IVertexData
|
||||
) : IVertexData {
|
||||
|
||||
/**
|
||||
* Convert to [MutableVertexData]
|
||||
*/
|
||||
fun toMutableVertexData(): MutableVertexData {
|
||||
return MutableVertexData(
|
||||
positions.toMutableList(),
|
||||
normals.toMutableList(),
|
||||
textureCoords.toMutableList(),
|
||||
colors.toMutableList(),
|
||||
tangents.toMutableList(),
|
||||
bitangents.toMutableList()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Mutable vertex data implementation
|
||||
*/
|
||||
class MutableVertexData(
|
||||
override val positions: MutableList<Vector3> = mutableListOf(),
|
||||
override val normals: MutableList<Vector3> = mutableListOf(),
|
||||
@@ -56,4 +77,19 @@ class MutableVertexData(
|
||||
override val colors: MutableList<ColorRGBa> = mutableListOf(),
|
||||
override val tangents: MutableList<Vector3> = mutableListOf(),
|
||||
override val bitangents: MutableList<Vector3> = mutableListOf()
|
||||
) : IVertexData
|
||||
) : IVertexData {
|
||||
|
||||
/**
|
||||
* Convert to [VertexData]
|
||||
*/
|
||||
fun toVertexData(): VertexData {
|
||||
return VertexData(
|
||||
positions.toList(),
|
||||
normals.toList(),
|
||||
textureCoords.toList(),
|
||||
colors.toList(),
|
||||
tangents.toList(),
|
||||
bitangents.toList()
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -2,12 +2,17 @@ package org.openrndr.extra.objloader
|
||||
|
||||
import org.openrndr.math.Vector3
|
||||
|
||||
/**
|
||||
* Extract wireframe from mesh data
|
||||
*/
|
||||
fun IMeshData.wireframe(): List<List<Vector3>> {
|
||||
return polygons.map { ip -> ip.toPolygon(this.vertexData).positions.toList() }
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Extract wireframe from compound mesh data
|
||||
*/
|
||||
fun ICompoundMeshData.wireframe(): List<List<Vector3>> {
|
||||
return compounds.values.flatMap {
|
||||
it.wireframe()
|
||||
}
|
||||
return compounds.values.flatMap { it.wireframe() }
|
||||
}
|
||||
57
orx-mesh/src/jvmMain/kotlin/VertexBufferExtensions.kt
Normal file
57
orx-mesh/src/jvmMain/kotlin/VertexBufferExtensions.kt
Normal file
@@ -0,0 +1,57 @@
|
||||
import org.openrndr.color.ColorRGBa
|
||||
import org.openrndr.draw.VertexBuffer
|
||||
import org.openrndr.extra.objloader.Polygon
|
||||
import org.openrndr.extra.objloader.objVertexFormat
|
||||
import org.openrndr.math.Vector2
|
||||
import org.openrndr.math.Vector3
|
||||
import java.nio.ByteBuffer
|
||||
import java.nio.ByteOrder
|
||||
|
||||
|
||||
private fun ByteBuffer.getVector3(): Vector3 {
|
||||
val x = getFloat()
|
||||
val y = getFloat()
|
||||
val z = getFloat()
|
||||
return Vector3(x.toDouble(), y.toDouble(), z.toDouble())
|
||||
}
|
||||
|
||||
private fun ByteBuffer.getVector2(): Vector2 {
|
||||
val x = getFloat()
|
||||
val y = getFloat()
|
||||
return Vector2(x.toDouble(), y.toDouble())
|
||||
}
|
||||
|
||||
private fun ByteBuffer.getColorRGBa(): ColorRGBa {
|
||||
val r = getFloat()
|
||||
val g = getFloat()
|
||||
val b = getFloat()
|
||||
val a = getFloat()
|
||||
return ColorRGBa(r.toDouble(), g.toDouble(), b.toDouble(), a.toDouble())
|
||||
}
|
||||
|
||||
/**
|
||||
Convert vertex buffer contents to a list of [Polygon] instances
|
||||
*/
|
||||
fun VertexBuffer.toPolygons(vertexCount: Int = this.vertexCount): List<Polygon> {
|
||||
require(vertexFormat == objVertexFormat)
|
||||
val triangleCount = vertexCount / 3
|
||||
val buffer = ByteBuffer.allocateDirect(this.vertexCount * vertexFormat.size)
|
||||
buffer.order(ByteOrder.nativeOrder())
|
||||
|
||||
val polygons = mutableListOf<Polygon>()
|
||||
for (t in 0 until triangleCount) {
|
||||
val positions = mutableListOf<Vector3>()
|
||||
val normals = mutableListOf<Vector3>()
|
||||
val textureCoordinates = mutableListOf<Vector2>()
|
||||
val colors = mutableListOf<ColorRGBa>()
|
||||
|
||||
for (v in 0 until 3) {
|
||||
positions.add(buffer.getVector3())
|
||||
normals.add(buffer.getVector3())
|
||||
textureCoordinates.add(buffer.getVector2())
|
||||
colors.add(buffer.getColorRGBa())
|
||||
}
|
||||
polygons.add(Polygon(positions, normals, textureCoordinates, colors))
|
||||
}
|
||||
return polygons
|
||||
}
|
||||
Reference in New Issue
Block a user