From 6e6cfe0d4c4ee5273b985d3c03b8fd97a2b21319 Mon Sep 17 00:00:00 2001 From: edwin Date: Fri, 23 Nov 2018 14:38:12 +0100 Subject: [PATCH] Added orx-obj-loader --- README.md | 79 +++++------ build.gradle | 4 +- orx-obj-loader/README.md | 18 +++ orx-obj-loader/src/main/kotlin/OBJLoader.kt | 140 ++++++++++++++++++++ settings.gradle | 3 +- 5 files changed, 202 insertions(+), 42 deletions(-) create mode 100644 orx-obj-loader/README.md create mode 100644 orx-obj-loader/src/main/kotlin/OBJLoader.kt diff --git a/README.md b/README.md index 237fe608..678fd9a3 100644 --- a/README.md +++ b/README.md @@ -1,39 +1,40 @@ -# ORX (OPENRNDR EXTRA) - -[![](https://jitpack.io/v/openrndr/orx.svg)](https://jitpack.io/#openrndr/orx) - -A growing library of assorted data structures, algorithms and utilities. - -- [`orx-compositor`](orx-compositor/README.md), a simple toolkit to make composite (layered) images -- [`orx-filter-extension`](orx-filter-extension/README.md), Program extension method that provides Filter based `extend()` -- [`orx-integral-image`](orx-integral-image/README.md), a CPU-based implementation for integral images (summed area tables) -- `orx-jumpflood`, a filter/shader based implementation of the jump flood algorithm for finding fast approximate (directional) distance fields -- `orx-kdtree`, a kd-tree implementation for fast nearest point searches -- [`orx-mesh-generators`](orx-mesh-generators/README.md), triangular mesh generators -- [`orx-no-clear`](orx-no-clear/README.md), a simple extension that provides drawing without clearing the background - -## Usage -ORX 0.0.13 is built against OPENRNDR 0.3.29, make sure you use this version in your project. Because OPENRNDR's API is pre 1.0 it tends to change from time to time. - -The easiest way to add ORX to your project is through the use of Jitpack. [Jitpack](http://jitpack.io) is a service that pulls Gradle based libraries from Github, builds them and serves the jar files. - -To setup Jitpack support in your project all you have to do is add the Jitpack repository to your `repositories {}`. It is advised to have the jitpack repository as the last entry. -``` -repositories { - maven { url 'https://jitpack.io' } -} -``` - -You can then add any of the ORX artefacts to your `dependencies {}`: -``` -dependencies { - compile 'com.github.openrndr.orx::v0.0.13' -} -``` - -For example if you want to use the `orx-no-clear` artifact one would use: -``` -dependencies { - compile 'com.github.openrndr.orx:orx-no-clear:v0.0.13' -} -``` +# ORX (OPENRNDR EXTRA) + +[![](https://jitpack.io/v/openrndr/orx.svg)](https://jitpack.io/#openrndr/orx) + +A growing library of assorted data structures, algorithms and utilities. + +- [`orx-compositor`](orx-compositor/README.md), a simple toolkit to make composite (layered) images +- [`orx-filter-extension`](orx-filter-extension/README.md), Program extension method that provides Filter based `extend()` +- [`orx-integral-image`](orx-integral-image/README.md), a CPU-based implementation for integral images (summed area tables) +- `orx-jumpflood`, a filter/shader based implementation of the jump flood algorithm for finding fast approximate (directional) distance fields +- `orx-kdtree`, a kd-tree implementation for fast nearest point searches +- [`orx-mesh-generators`](orx-mesh-generators/README.md), triangular mesh generators +- [`orx-no-clear`](orx-no-clear/README.md), a simple extension that provides drawing without clearing the background +- [`orx-obj-loader`](orx-obj-loader/README.md), simple Wavefront .obj mesh loader + +## Usage +ORX 0.0.14 is built against OPENRNDR 0.3.30-rc1, make sure you use this version in your project. Because OPENRNDR's API is pre 1.0 it tends to change from time to time. + +The easiest way to add ORX to your project is through the use of Jitpack. [Jitpack](http://jitpack.io) is a service that pulls Gradle based libraries from Github, builds them and serves the jar files. + +To setup Jitpack support in your project all you have to do is add the Jitpack repository to your `repositories {}`. It is advised to have the jitpack repository as the last entry. +``` +repositories { + maven { url 'https://jitpack.io' } +} +``` + +You can then add any of the ORX artefacts to your `dependencies {}`: +``` +dependencies { + compile 'com.github.openrndr.orx::v0.0.14' +} +``` + +For example if you want to use the `orx-no-clear` artifact one would use: +``` +dependencies { + compile 'com.github.openrndr.orx:orx-no-clear:v0.0.14' +} +``` diff --git a/build.gradle b/build.gradle index c247600b..26c597ea 100644 --- a/build.gradle +++ b/build.gradle @@ -4,7 +4,7 @@ plugins { allprojects { group 'org.openrndr.extra' - version '0.0.13' + version '0.0.14' } repositories { @@ -13,7 +13,7 @@ repositories { } ext { - openrndrVersion = "0.3.29" + openrndrVersion = "0.3.30-rc1" } subprojects { diff --git a/orx-obj-loader/README.md b/orx-obj-loader/README.md new file mode 100644 index 00000000..bf1460c7 --- /dev/null +++ b/orx-obj-loader/README.md @@ -0,0 +1,18 @@ +# orx-obj-loader + +A simple loader for Wavefront .obj files + +##### Usage + +Loading directly into a vertex buffer can be done through `loadOBJasVertexBuffer`. + +```kotlin +val vertexBuffer = loadOBJasVertexBuffer("data/someObject.obj") +``` + +The loaded vertex buffer can be drawn like this: +```kotlin +drawer.vertexBuffer(vertexBuffer, DrawPrimitive.TRIANGLES) +``` + + diff --git a/orx-obj-loader/src/main/kotlin/OBJLoader.kt b/orx-obj-loader/src/main/kotlin/OBJLoader.kt new file mode 100644 index 00000000..931d6b74 --- /dev/null +++ b/orx-obj-loader/src/main/kotlin/OBJLoader.kt @@ -0,0 +1,140 @@ +package modeling + +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 java.io.File +import java.net.MalformedURLException +import java.net.URL + +class Triangle(val positions: Array, val normals: Array) { + fun transform(t: Matrix44): Triangle { + return Triangle(positions.map { (t * it.xyz1).div }.toTypedArray(), normals) + } +} + +class Box(val corner: Vector3, val width: Double, val height: Double, val depth: Double) + +fun bounds(triangles: List): Box { + var minX = Double.POSITIVE_INFINITY + var minY = Double.POSITIVE_INFINITY + var minZ = Double.POSITIVE_INFINITY + + var maxX = Double.NEGATIVE_INFINITY + var maxY = Double.NEGATIVE_INFINITY + var maxZ = Double.NEGATIVE_INFINITY + + triangles.forEach { + it.positions.forEach { + minX = Math.min(minX, it.x) + minY = Math.min(minY, it.y) + minZ = Math.min(minZ, it.z) + + maxX = Math.max(maxX, it.x) + maxY = Math.max(maxY, it.y) + maxZ = Math.max(maxZ, it.z) + } + } + return Box(Vector3(minX, minY, minZ), maxX - minX, maxY - minY, maxZ - minZ) +} + +fun loadOBJ(fileOrUrl: String): Map> { + return try { + val url = URL(fileOrUrl) + loadOBJ(url) + } catch (e: MalformedURLException) { + loadOBJ(File(fileOrUrl)) + } +} + +private val objVertexFormat = vertexFormat { + position(3) + normal(3) + textureCoordinate(2) +} + +fun loadOBJasVertexBuffer(fileOrUrl: String): VertexBuffer { + return try { + val url = URL(fileOrUrl) + loadOBJasVertexBuffer(url) + } catch (e: MalformedURLException) { + loadOBJasVertexBuffer(File(fileOrUrl)) + } +} + +fun loadOBJasVertexBuffer(url: URL): VertexBuffer = loadOBJasVertexBuffer(url.readText().split("\n")) +fun loadOBJasVertexBuffer(file: File): VertexBuffer = loadOBJasVertexBuffer(file.readLines()) +fun loadOBJasVertexBuffer(lines: List): VertexBuffer { + val objects = loadOBJ(lines) + val triangleCount = objects.values.sumBy { it.size } + val vertexBuffer = vertexBuffer(objVertexFormat, triangleCount * 3) + + vertexBuffer.put { + objects.entries.forEach { + it.value.forEach { + for (i in 0 until it.positions.size) { + write(it.positions[i]) + write(it.normals[i]) + write(Vector2.ZERO) + } + } + } + } + + vertexBuffer.shadow.destroy() + return vertexBuffer +} + +fun loadOBJ(file: File): Map> = loadOBJ(file.readLines()) +fun loadOBJ(url: URL): Map> = loadOBJ(url.readText().split("\n")) + +fun loadOBJ(lines: List): Map> { + val meshes = mutableMapOf>() + val positions = mutableListOf() + val normals = mutableListOf() + var activeMesh = mutableListOf() + + lines.forEach { line -> + if (line.isNotEmpty()) { + val tokens = line.split(Regex("[ |\t]+")).map { it.trim() }.filter { it.isNotEmpty() } + + if (tokens.isNotEmpty()) { + when (tokens[0]) { + "v" -> { + positions += Vector3(tokens[1].toDouble(), tokens[2].toDouble(), tokens[3].toDouble()) + } + "vn" -> normals += Vector3(tokens[1].toDouble(), tokens[2].toDouble(), tokens[3].toDouble()) + "g" -> { + activeMesh = mutableListOf() + meshes[tokens[1]] = activeMesh + } + "f" -> { + val indices = tokens.subList(1, tokens.size).map { it.split("/") }.map { + it.map { it.toIntOrNull() } + } + + if (indices.size == 3) { + val ps = arrayOf( + indices[0][0]?.let { positions[it - 1] } ?: Vector3.ZERO, + indices[1][0]?.let { positions[it - 1] } ?: Vector3.ZERO, + indices[2][0]?.let { positions[it - 1] } ?: Vector3.ZERO) + + val ns = arrayOf( + indices[0][2]?.let { normals[it - 1] } ?: Vector3.ZERO, + indices[1][2]?.let { normals[it - 1] } ?: Vector3.ZERO, + indices[2][2]?.let { normals[it - 1] } ?: Vector3.ZERO) + + activeMesh.add(Triangle(ps, ns)) + } else { + TODO("implement non triangular surfaces ${indices.size}") + } + } + } + } + } + } + return meshes +} \ No newline at end of file diff --git a/settings.gradle b/settings.gradle index bb06a579..d082eaf0 100644 --- a/settings.gradle +++ b/settings.gradle @@ -6,7 +6,8 @@ include 'orx-compositor', 'orx-jumpflood', 'orx-kdtree', 'orx-mesh-generators', - 'orx-no-clear' + 'orx-no-clear', + 'orx-obj-loader'