From 149a7fd1838f1054dd539b9265edfb4663e420ef Mon Sep 17 00:00:00 2001 From: Edwin Jakobs Date: Sat, 26 Jan 2019 21:24:58 +0100 Subject: [PATCH] changes --- README.md | 84 ++--- ShaderError.txt | 24 ++ build.gradle | 132 +++---- orx-camera/README.md | 4 +- orx-camera/src/main/kotlin/Debug3D.kt | 146 ++++---- orx-camera/src/main/kotlin/OrbitalCamera.kt | 259 +++++++------ orx-camera/src/main/kotlin/OrbitalControls.kt | 228 +++++++----- orx-compositor/src/main/kotlin/Compositor.kt | 274 +++++++------- orx-examples/build.gradle | 31 ++ .../gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 54413 bytes .../gradle/wrapper/gradle-wrapper.properties | 6 + orx-examples/gradlew | 172 +++++++++ orx-examples/gradlew.bat | 84 +++++ orx-examples/settings.gradle | 2 + orx-examples/src/main/kotlin/jumpfil-001.kt | 56 +++ orx-examples/src/main/kotlin/jumpfil-002.kt | 45 +++ .../src/main/kotlin/FastIntegralImage.kt | 152 ++++---- .../resources/shaders/gl3/integral-image.frag | 50 +-- orx-jumpflood/src/main/kotlin/JumpFlood.kt | 254 ++++++------- .../resources/shaders/gl3/pixel-distance.frag | 30 +- orx-mesh-generators/src/main/kotlin/Box.kt | 120 +++--- orx-mesh-generators/src/main/kotlin/Cap.kt | 200 +++++----- .../src/main/kotlin/Cylinder.kt | 162 ++++----- .../src/main/kotlin/GeneratorBuffer.kt | 342 +++++++++--------- orx-mesh-generators/src/main/kotlin/Plane.kt | 166 ++++----- orx-mesh-generators/src/main/kotlin/Sphere.kt | 166 ++++----- orx-no-clear/README.md | 106 +++--- orx-no-clear/src/main/kotlin/NoClear.kt | 112 +++--- orx-noise/README.md | 244 ++++++------- orx-noise/src/main/kotlin/CubicNoise2D.kt | 54 +-- orx-noise/src/main/kotlin/CubicNoise3D.kt | 100 ++--- orx-noise/src/main/kotlin/Fractal.kt | 210 +++++------ orx-noise/src/main/kotlin/GradCoord.kt | 312 ++++++++-------- orx-noise/src/main/kotlin/Interpolation.kt | 46 +-- orx-noise/src/main/kotlin/MathUtils.kt | 10 +- orx-noise/src/main/kotlin/PerlinNoise2D.kt | 50 +-- orx-noise/src/main/kotlin/PerlinNoise3D.kt | 68 ++-- orx-noise/src/main/kotlin/SimplexNoise2D.kt | 124 +++---- orx-noise/src/main/kotlin/SimplexNoise3D.kt | 186 +++++----- orx-noise/src/main/kotlin/UniformRandom.kt | 142 ++++---- orx-noise/src/main/kotlin/ValueNoise2D.kt | 40 +- orx-noise/src/main/kotlin/ValueNoise3D.kt | 56 +-- 42 files changed, 2758 insertions(+), 2291 deletions(-) create mode 100644 ShaderError.txt create mode 100644 orx-examples/build.gradle create mode 100644 orx-examples/gradle/wrapper/gradle-wrapper.jar create mode 100644 orx-examples/gradle/wrapper/gradle-wrapper.properties create mode 100644 orx-examples/gradlew create mode 100644 orx-examples/gradlew.bat create mode 100644 orx-examples/settings.gradle create mode 100644 orx-examples/src/main/kotlin/jumpfil-001.kt create mode 100644 orx-examples/src/main/kotlin/jumpfil-002.kt diff --git a/README.md b/README.md index 24f5da977..b188ab2dc 100644 --- a/README.md +++ b/README.md @@ -1,42 +1,42 @@ -# 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-camera`](orx-camera/README.md), 3d camera and controls -- [`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-noise`](orx-noise/README.md), library for random number generation and noise -- [`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.19 is built against OPENRNDR 0.3.32, 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.19' -} -``` - -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.19' -} -``` +# 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-camera`](orx-camera/README.md), 3d camera and controls +- [`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-noise`](orx-noise/README.md), library for random number generation and noise +- [`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.19 is built against OPENRNDR 0.3.32, 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.19' +} +``` + +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.19' +} +``` diff --git a/ShaderError.txt b/ShaderError.txt new file mode 100644 index 000000000..ffda7e1a0 --- /dev/null +++ b/ShaderError.txt @@ -0,0 +1,24 @@ +#version 330 core + +uniform sampler2D tex0; +in vec2 v_texCoord0; + +out vec4 o_color; + +void main() { + vec2 step = 1.0 / textureSize(tex0, 0); + float ref = step(0.5 , texture(tex0, v_texCoord0).r); + vec4 outc = vec4(-1.0, -1.0, 0.0, 1.0); + + float contour = 0.0; + for (y = -1; y <= 1; ++y) { + for (x = -1; x <= 1; ++x) { + float smp = step(0.5, texture(tex0, v_texCoord0 + vec2(x,y) * step).r); + if (smp != ref) { + contour = 1.0; + } + } + } + + o_color = vec4(contour, contour, contour, 1.0); +} \ No newline at end of file diff --git a/build.gradle b/build.gradle index fe20fff46..989870562 100644 --- a/build.gradle +++ b/build.gradle @@ -1,67 +1,67 @@ -plugins { - id 'org.jetbrains.kotlin.jvm' version '1.3.10' -} - -allprojects { - group 'org.openrndr.extra' - version '0.0.19' -} - -repositories { - mavenLocal() - mavenCentral() -} - -ext { - openrndrVersion = "0.3.32-rc1" -} - -subprojects { - - apply plugin: 'kotlin' - apply plugin: 'maven' - apply plugin: 'maven-publish' - repositories { - mavenLocal() - mavenCentral() - maven { - url = "https://dl.bintray.com/openrndr/openrndr" - } - } - - dependencies { - 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' - } - - publishing { - publications { - mavenJava(MavenPublication) { - from components.java - - artifact sourceJar - } - } - } - - task sourceJar(type: Jar) { - classifier = 'sources' - from sourceSets.main.kotlin - } - - - -} - -dependencies { - compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8" -} - -compileKotlin { - kotlinOptions.jvmTarget = "1.8" -} -compileTestKotlin { - kotlinOptions.jvmTarget = "1.8" +plugins { + id 'org.jetbrains.kotlin.jvm' version '1.3.10' +} + +allprojects { + group 'org.openrndr.extra' + version '0.0.20' +} + +repositories { + mavenLocal() + mavenCentral() +} + +ext { + openrndrVersion = "0.3.32-rc1" +} + +subprojects { + + apply plugin: 'kotlin' + apply plugin: 'maven' + apply plugin: 'maven-publish' + repositories { + mavenLocal() + mavenCentral() + maven { + url = "https://dl.bintray.com/openrndr/openrndr" + } + } + + dependencies { + 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' + } + + publishing { + publications { + mavenJava(MavenPublication) { + from components.java + + artifact sourceJar + } + } + } + + task sourceJar(type: Jar) { + classifier = 'sources' + from sourceSets.main.kotlin + } + + + +} + +dependencies { + compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8" +} + +compileKotlin { + kotlinOptions.jvmTarget = "1.8" +} +compileTestKotlin { + kotlinOptions.jvmTarget = "1.8" } \ No newline at end of file diff --git a/orx-camera/README.md b/orx-camera/README.md index 17b752cc4..c9acabc9b 100644 --- a/orx-camera/README.md +++ b/orx-camera/README.md @@ -1,3 +1,3 @@ -# orx-camera - +# orx-camera + 3D camera and controls for OPENRNDR. This supersedes the to be deprecated functionality in OPENRNDR. \ No newline at end of file diff --git a/orx-camera/src/main/kotlin/Debug3D.kt b/orx-camera/src/main/kotlin/Debug3D.kt index d29786957..f19878c32 100644 --- a/orx-camera/src/main/kotlin/Debug3D.kt +++ b/orx-camera/src/main/kotlin/Debug3D.kt @@ -1,74 +1,74 @@ -package org.openrndr.extras.camera - -import org.openrndr.Extension -import org.openrndr.Program -import org.openrndr.color.ColorRGBa -import org.openrndr.draw.* -import org.openrndr.math.Matrix44 -import org.openrndr.math.Vector3 - -@Suppress("unused") -class Debug3D(eye: Vector3 = Vector3(0.0, 0.0, 10.0), lookAt: Vector3 = Vector3.ZERO, private val fov: Double = 90.0) : Extension { - - override var enabled: Boolean = true - var showGrid = false - val orbitalCamera = OrbitalCamera(eye, lookAt) - private val orbitalControls = OrbitalControls(orbitalCamera) - private var lastSeconds: Double = -1.0 - - private val grid = vertexBuffer( - vertexFormat { - position(3) - } - , 4 * 21).apply { - put { - for (x in -10..10) { - write(Vector3(x.toDouble(), 0.0, -10.0)) - write(Vector3(x.toDouble(), 0.0, 10.0)) - write(Vector3(-10.0, 0.0, x.toDouble())) - write(Vector3(10.0, 0.0, x.toDouble())) - } - } - } - - override fun beforeDraw(drawer: Drawer, program: Program) { - if (lastSeconds == -1.0) lastSeconds = program.seconds - - val delta = program.seconds - lastSeconds - lastSeconds = program.seconds - orbitalCamera.update(delta) - - drawer.background(ColorRGBa.BLACK) - drawer.perspective(fov, program.window.size.x / program.window.size.y, 0.1, 1000.0) - drawer.view = orbitalCamera.viewMatrix() - - if (showGrid) { - drawer.isolated { - drawer.fill = ColorRGBa.WHITE - drawer.stroke = ColorRGBa.WHITE - drawer.vertexBuffer(grid, DrawPrimitive.LINES) - - // Axis cross - drawer.fill = ColorRGBa.RED - drawer.lineSegment(Vector3.ZERO, Vector3.UNIT_X) - - drawer.fill = ColorRGBa.GREEN - drawer.lineSegment(Vector3.ZERO, Vector3.UNIT_Y) - - drawer.fill = ColorRGBa.BLUE - drawer.lineSegment(Vector3.ZERO, Vector3.UNIT_Z) - } - } - } - - override fun afterDraw(drawer: Drawer, program: Program) { - drawer.isolated { - drawer.view = Matrix44.IDENTITY - drawer.ortho() - } - } - - override fun setup(program: Program) { - orbitalControls.setup(program) - } +package org.openrndr.extras.camera + +import org.openrndr.Extension +import org.openrndr.Program +import org.openrndr.color.ColorRGBa +import org.openrndr.draw.* +import org.openrndr.math.Matrix44 +import org.openrndr.math.Vector3 + +@Suppress("unused") +class Debug3D(eye: Vector3 = Vector3(0.0, 0.0, 10.0), lookAt: Vector3 = Vector3.ZERO, fov:Double = 90.0) : Extension { + + override var enabled: Boolean = true + var showGrid = false + val orbitalCamera = OrbitalCamera(eye, lookAt, 90.0) + private val orbitalControls = OrbitalControls(orbitalCamera) + private var lastSeconds: Double = -1.0 + + private val grid = vertexBuffer( + vertexFormat { + position(3) + } + , 4 * 21).apply { + put { + for (x in -10..10) { + write(Vector3(x.toDouble(), 0.0, -10.0)) + write(Vector3(x.toDouble(), 0.0, 10.0)) + write(Vector3(-10.0, 0.0, x.toDouble())) + write(Vector3(10.0, 0.0, x.toDouble())) + } + } + } + + override fun beforeDraw(drawer: Drawer, program: Program) { + if (lastSeconds == -1.0) lastSeconds = program.seconds + + val delta = program.seconds - lastSeconds + lastSeconds = program.seconds + orbitalCamera.update(delta) + + drawer.background(ColorRGBa.BLACK) + drawer.perspective(orbitalCamera.fov, program.window.size.x / program.window.size.y, 0.1, 1000.0) + drawer.view = orbitalCamera.viewMatrix() + + if (showGrid) { + drawer.isolated { + drawer.fill = ColorRGBa.WHITE + drawer.stroke = ColorRGBa.WHITE + drawer.vertexBuffer(grid, DrawPrimitive.LINES) + + // Axis cross + drawer.fill = ColorRGBa.RED + drawer.lineSegment(Vector3.ZERO, Vector3.UNIT_X) + + drawer.fill = ColorRGBa.GREEN + drawer.lineSegment(Vector3.ZERO, Vector3.UNIT_Y) + + drawer.fill = ColorRGBa.BLUE + drawer.lineSegment(Vector3.ZERO, Vector3.UNIT_Z) + } + } + } + + override fun afterDraw(drawer: Drawer, program: Program) { + drawer.isolated { + drawer.view = Matrix44.IDENTITY + drawer.ortho() + } + } + + override fun setup(program: Program) { + orbitalControls.setup(program) + } } \ No newline at end of file diff --git a/orx-camera/src/main/kotlin/OrbitalCamera.kt b/orx-camera/src/main/kotlin/OrbitalCamera.kt index 15e210ade..dbc8117b1 100644 --- a/orx-camera/src/main/kotlin/OrbitalCamera.kt +++ b/orx-camera/src/main/kotlin/OrbitalCamera.kt @@ -1,120 +1,139 @@ -package org.openrndr.extras.camera - -import org.openrndr.* -import org.openrndr.color.ColorRGBa -import org.openrndr.draw.DrawPrimitive -import org.openrndr.draw.Drawer -import org.openrndr.draw.isolated -import org.openrndr.draw.vertexBuffer -import org.openrndr.draw.vertexFormat -import org.openrndr.math.Matrix44 -import org.openrndr.math.Spherical -import org.openrndr.math.Vector2 -import org.openrndr.math.Vector3 -import org.openrndr.math.transforms.lookAt as lookAt_ - -class OrbitalCamera(eye: Vector3, lookAt: Vector3) { - - // current position in spherical coordinates - var spherical = Spherical.fromVector(eye) - private set - var lookAt = lookAt - private set - - private var sphericalEnd = Spherical.fromVector(eye) - private var lookAtEnd = lookAt.copy() - private var dirty: Boolean = true - - var dampingFactor = 0.05 - var zoomSpeed = 1.0 - - fun rotate(rotX: Double, rotY: Double) { - sphericalEnd += Spherical(0.0, rotX, rotY) - sphericalEnd = sphericalEnd.makeSafe() - dirty = true - } - - fun rotateTo(rotX: Double, rotY: Double) { - sphericalEnd = sphericalEnd.copy(theta = rotX, phi = rotY) - sphericalEnd = sphericalEnd.makeSafe() - dirty = true - } - - fun rotateTo(eye: Vector3) { - sphericalEnd = Spherical.fromVector(eye) - sphericalEnd = sphericalEnd.makeSafe() - dirty = true - } - - fun dollyIn() { - val zoomScale = Math.pow(0.95, zoomSpeed) - dolly(sphericalEnd.radius * zoomScale - sphericalEnd.radius) - } - - fun dollyOut() { - val zoomScale = Math.pow(0.95, zoomSpeed) - dolly(sphericalEnd.radius / zoomScale - sphericalEnd.radius) - } - - private fun dolly(distance: Double) { - sphericalEnd += Spherical(distance, 0.0, 0.0) - dirty = true - } - - fun pan(x: Double, y: Double, z: Double) { - val view = viewMatrix() - val xColumn = Vector3(view.c0r0, view.c1r0, view.c2r0) * x - val yColumn = Vector3(view.c0r1, view.c1r1, view.c2r1) * y - val zColumn = Vector3(view.c0r2, view.c1r2, view.c2r2) * z - lookAtEnd += xColumn + yColumn + zColumn - dirty = true - } - - fun panTo(target : Vector3) { - lookAtEnd = target - dirty = true - } - - fun dollyTo(distance: Double) { - sphericalEnd = sphericalEnd.copy(radius = distance ) - dirty = true - } - - fun update(timeDelta: Double) { - if (!dirty) return - dirty = false - - val dampingFactor = dampingFactor * timeDelta / 0.0060 - val sphericalDelta = sphericalEnd - spherical - val lookAtDelta = lookAtEnd - lookAt - - if ( - Math.abs(sphericalEnd.radius) > EPSILON || - Math.abs(sphericalEnd.theta) > EPSILON || - Math.abs(sphericalEnd.phi) > EPSILON || - Math.abs(lookAtDelta.x) > EPSILON || - Math.abs(lookAtDelta.y) > EPSILON || - Math.abs(lookAtDelta.z) > EPSILON - ) { - - spherical += (sphericalDelta * dampingFactor) - lookAt += (lookAtDelta * dampingFactor) - dirty = true - - } else { - spherical = sphericalEnd.copy() - lookAt = lookAtEnd.copy() - } - spherical = spherical.makeSafe() - } - - fun viewMatrix(): Matrix44 { - return lookAt_(Vector3.fromSpherical(spherical) + lookAt, lookAt, Vector3.UNIT_Y) - } - - companion object { - private const val EPSILON = 0.000001 - } -} - - +package org.openrndr.extras.camera + +import org.openrndr.* +import org.openrndr.color.ColorRGBa +import org.openrndr.draw.DrawPrimitive +import org.openrndr.draw.Drawer +import org.openrndr.draw.isolated +import org.openrndr.draw.vertexBuffer +import org.openrndr.draw.vertexFormat +import org.openrndr.math.Matrix44 +import org.openrndr.math.Spherical +import org.openrndr.math.Vector2 +import org.openrndr.math.Vector3 +import org.openrndr.math.transforms.lookAt as lookAt_ + +class OrbitalCamera(eye: Vector3, lookAt: Vector3, var fov:Double) { + + + // current position in spherical coordinates + var spherical = Spherical.fromVector(eye) + private set + var lookAt = lookAt + private set + + private var sphericalEnd = Spherical.fromVector(eye) + private var lookAtEnd = lookAt.copy() + private var dirty: Boolean = true + + var fovEnd = fov + + var dampingFactor = 0.05 + var zoomSpeed = 1.0 + + fun setView(lookAt: Vector3, spherical: Spherical, fov:Double) { + this.lookAt = lookAt + this.lookAtEnd = lookAt + this.spherical = spherical + this.sphericalEnd = spherical + this.fov = fov + this.fovEnd= fov + } + + fun rotate(rotX: Double, rotY: Double) { + sphericalEnd += Spherical(0.0, rotX, rotY) + sphericalEnd = sphericalEnd.makeSafe() + dirty = true + } + + fun rotateTo(rotX: Double, rotY: Double) { + sphericalEnd = sphericalEnd.copy(theta = rotX, phi = rotY) + sphericalEnd = sphericalEnd.makeSafe() + dirty = true + } + + fun rotateTo(eye: Vector3) { + sphericalEnd = Spherical.fromVector(eye) + sphericalEnd = sphericalEnd.makeSafe() + dirty = true + } + + fun dollyIn() { + val zoomScale = Math.pow(0.95, zoomSpeed) + dolly(sphericalEnd.radius * zoomScale - sphericalEnd.radius) + } + + fun dollyOut() { + val zoomScale = Math.pow(0.95, zoomSpeed) + dolly(sphericalEnd.radius / zoomScale - sphericalEnd.radius) + } + + fun dolly(distance: Double) { + sphericalEnd += Spherical(distance, 0.0, 0.0) + dirty = true + } + + fun pan(x: Double, y: Double, z: Double) { + val view = viewMatrix() + val xColumn = Vector3(view.c0r0, view.c1r0, view.c2r0) * x + val yColumn = Vector3(view.c0r1, view.c1r1, view.c2r1) * y + val zColumn = Vector3(view.c0r2, view.c1r2, view.c2r2) * z + lookAtEnd += xColumn + yColumn + zColumn + dirty = true + } + + fun panTo(target : Vector3) { + lookAtEnd = target + dirty = true + } + + fun dollyTo(distance: Double) { + sphericalEnd = sphericalEnd.copy(radius = distance ) + dirty = true + } + + fun zoom(degrees: Double) { + fovEnd += degrees + } + + fun update(timeDelta: Double) { + if (!dirty) return + dirty = false + + val dampingFactor = dampingFactor * timeDelta / 0.0060 + val sphericalDelta = sphericalEnd - spherical + val lookAtDelta = lookAtEnd - lookAt + val fovDelta = fovEnd - fov + if ( + Math.abs(sphericalEnd.radius) > EPSILON || + Math.abs(sphericalEnd.theta) > EPSILON || + Math.abs(sphericalEnd.phi) > EPSILON || + Math.abs(lookAtDelta.x) > EPSILON || + Math.abs(lookAtDelta.y) > EPSILON || + Math.abs(lookAtDelta.z) > EPSILON || + Math.abs(fovDelta) > EPSILON + ) { + + fov += (fovDelta * dampingFactor) + spherical += (sphericalDelta * dampingFactor) + spherical = spherical.makeSafe() + lookAt += (lookAtDelta * dampingFactor) + dirty = true + + } else { + spherical = sphericalEnd.copy() + lookAt = lookAtEnd.copy() + } + spherical = spherical.makeSafe() + } + + fun viewMatrix(): Matrix44 { + return lookAt_(Vector3.fromSpherical(spherical) + lookAt, lookAt, Vector3.UNIT_Y) + } + + companion object { + private const val EPSILON = 0.000001 + } +} + + diff --git a/orx-camera/src/main/kotlin/OrbitalControls.kt b/orx-camera/src/main/kotlin/OrbitalControls.kt index 10ef3c799..24ce23a57 100644 --- a/orx-camera/src/main/kotlin/OrbitalControls.kt +++ b/orx-camera/src/main/kotlin/OrbitalControls.kt @@ -1,100 +1,128 @@ -package org.openrndr.extras.camera - -import org.openrndr.* -import org.openrndr.math.Vector2 -import org.openrndr.math.Vector3 - -class OrbitalControls(val orbitalCamera: OrbitalCamera) { - enum class STATE { - NONE, - ROTATE, - PAN, - } - - private var state = STATE.NONE - var fov = 90.0 - - private lateinit var program: Program - private lateinit var lastMousePosition: Vector2 - - private fun mouseScrolled(event: MouseEvent) { - - if (Math.abs(event.rotation.x) > 0.1) return - - when { - event.rotation.y > 0 -> orbitalCamera.dollyIn() - event.rotation.y < 0 -> orbitalCamera.dollyOut() - } - } - - private fun mouseMoved(event: MouseEvent) { - - if (state == STATE.NONE) return - val delta = lastMousePosition - event.position - lastMousePosition = event.position - - if (state == STATE.PAN) { - - val offset = Vector3.fromSpherical(orbitalCamera.spherical) - orbitalCamera.lookAt - - // half of the fov is center to top of screen - val targetDistance = offset.length * Math.tan((fov / 2) * Math.PI / 180) - val panX = (2 * delta.x * targetDistance / program.window.size.x) - val panY = (2 * delta.y * targetDistance / program.window.size.y) - - orbitalCamera.pan(panX, -panY, 0.0) - - } else { - val rotX = 2 * Math.PI * delta.x / program.window.size.x - val rotY = 2 * Math.PI * delta.y / program.window.size.y - orbitalCamera.rotate(rotX, rotY) - } - - } - - private fun mouseButtonDown(event: MouseEvent) { - val previousState = state - - when (event.button) { - MouseButton.LEFT -> { - state = STATE.ROTATE - } - MouseButton.RIGHT -> { - state = STATE.PAN - } - MouseButton.CENTER -> { - } - MouseButton.NONE -> { - } - } - - if (previousState == STATE.NONE) { - lastMousePosition = event.position - } - } - - fun keyPressed(keyEvent: KeyEvent) { - if (keyEvent.key == KEY_ARROW_RIGHT) { - orbitalCamera.pan(1.0, 0.0, 0.0) - } - if (keyEvent.key == KEY_ARROW_LEFT) { - orbitalCamera.pan(-1.0, 0.0, 0.0) - } - if (keyEvent.key == KEY_ARROW_UP) { - orbitalCamera.pan(0.0, 1.0, 0.0) - } - if (keyEvent.key == KEY_ARROW_DOWN) { - orbitalCamera.pan(0.0, -1.0, 0.0) - } - } - - fun setup(program: Program) { - this.program = program - program.mouse.moved.listen { mouseMoved(it) } - program.mouse.buttonDown.listen { mouseButtonDown(it) } - program.mouse.buttonUp.listen { state = STATE.NONE } - program.mouse.scrolled.listen { mouseScrolled(it) } - program.keyboard.keyDown.listen { keyPressed(it) } - program.keyboard.keyRepeat.listen{ keyPressed(it) } - } -} +package org.openrndr.extras.camera + +import org.openrndr.* +import org.openrndr.math.Vector2 +import org.openrndr.math.Vector3 + +class OrbitalControls(val orbitalCamera: OrbitalCamera) { + enum class STATE { + NONE, + ROTATE, + PAN, + } + + private var state = STATE.NONE + var fov = 90.0 + + private lateinit var program: Program + private lateinit var lastMousePosition: Vector2 + + private fun mouseScrolled(event: MouseEvent) { + + if (Math.abs(event.rotation.x) > 0.1) return + + when { + event.rotation.y > 0 -> orbitalCamera.dollyIn() + event.rotation.y < 0 -> orbitalCamera.dollyOut() + } + } + + private fun mouseMoved(event: MouseEvent) { + + if (state == STATE.NONE) return + val delta = lastMousePosition - event.position + lastMousePosition = event.position + + if (state == STATE.PAN) { + + val offset = Vector3.fromSpherical(orbitalCamera.spherical) - orbitalCamera.lookAt + + // half of the fov is center to top of screen + val targetDistance = offset.length * Math.tan((fov / 2) * Math.PI / 180) + val panX = (2 * delta.x * targetDistance / program.window.size.x) + val panY = (2 * delta.y * targetDistance / program.window.size.y) + + orbitalCamera.pan(panX, -panY, 0.0) + + } else { + val rotX = 2 * Math.PI * delta.x / program.window.size.x + val rotY = 2 * Math.PI * delta.y / program.window.size.y + orbitalCamera.rotate(rotX, rotY) + } + + } + + private fun mouseButtonDown(event: MouseEvent) { + val previousState = state + + when (event.button) { + MouseButton.LEFT -> { + state = STATE.ROTATE + } + MouseButton.RIGHT -> { + state = STATE.PAN + } + MouseButton.CENTER -> { + } + MouseButton.NONE -> { + } + } + + if (previousState == STATE.NONE) { + lastMousePosition = event.position + } + } + + fun keyPressed(keyEvent: KeyEvent) { + if (keyEvent.key == KEY_ARROW_RIGHT) { + orbitalCamera.pan(1.0, 0.0, 0.0) + } + if (keyEvent.key == KEY_ARROW_LEFT) { + orbitalCamera.pan(-1.0, 0.0, 0.0) + } + if (keyEvent.key == KEY_ARROW_UP) { + orbitalCamera.pan(0.0, 1.0, 0.0) + } + if (keyEvent.key == KEY_ARROW_DOWN) { + orbitalCamera.pan(0.0, -1.0, 0.0) + } + + if (keyEvent.name == "q") { + orbitalCamera.pan(0.0, -1.0, 0.0) + } + if (keyEvent.name == "e") { + orbitalCamera.pan(0.0, 1.0, 0.0) + } + if (keyEvent.name == "w") { + orbitalCamera.pan(0.0, 0.0, -1.0) + } + if (keyEvent.name == "s") { + orbitalCamera.pan(0.0, 0.0, 1.0) + } + if (keyEvent.name == "a") { + orbitalCamera.pan(-1.0, 0.0, 0.0) + } + if (keyEvent.name == "d") { + orbitalCamera.pan(1.0, 0.0, 0.0) + } + + if (keyEvent.key == KEY_PAGE_UP) { + orbitalCamera.zoom(1.0) + } + + if (keyEvent.key == KEY_PAGE_DOWN) { + orbitalCamera.zoom(-1.0) + } + + } + + fun setup(program: Program) { + this.program = program + program.mouse.moved.listen { mouseMoved(it) } + program.mouse.buttonDown.listen { mouseButtonDown(it) } + program.mouse.buttonUp.listen { state = STATE.NONE } + program.mouse.scrolled.listen { mouseScrolled(it) } + program.keyboard.keyDown.listen { keyPressed(it) } + program.keyboard.keyRepeat.listen{ keyPressed(it) } + } +} diff --git a/orx-compositor/src/main/kotlin/Compositor.kt b/orx-compositor/src/main/kotlin/Compositor.kt index a7c383236..bf5f94c36 100644 --- a/orx-compositor/src/main/kotlin/Compositor.kt +++ b/orx-compositor/src/main/kotlin/Compositor.kt @@ -1,138 +1,138 @@ -package org.openrndr.extra.compositor - -import org.openrndr.color.ColorRGBa -import org.openrndr.draw.* -import org.openrndr.math.Matrix44 - - -private val postBufferCache = mutableListOf() - -fun RenderTarget.deepDestroy() { - val cbcopy = colorBuffers.map { it} - val dbcopy = depthBuffer - detachDepthBuffer() - detachColorBuffers() - cbcopy.forEach { - it.destroy() - } - dbcopy?.destroy() - destroy() -} - -/** - * A single layer representation - */ -class Layer internal constructor() { - var drawFunc: () -> Unit = {} - val children: MutableList = mutableListOf() - var blendFilter: Pair Unit>? = null - val postFilters: MutableList Unit>> = mutableListOf() - - private var layerTarget:RenderTarget? = null - - /** - * draw the layer - */ - fun draw(drawer: Drawer) { - val rt = RenderTarget.active - - val llt = layerTarget - if (llt == null || (llt.width != rt.width || llt.height != rt.height)) { - layerTarget?.deepDestroy() - layerTarget = renderTarget(rt.width, rt.height) { - colorBuffer() - depthBuffer() - } - } - - layerTarget?.let { target -> - drawer.isolatedWithTarget(target) { - drawer.background(ColorRGBa.TRANSPARENT) - drawFunc() - children.forEach { - it.draw(drawer) - } - } - - if (postFilters.size > 0) { - val sizeMismatch = if (postBufferCache.isNotEmpty()) { - postBufferCache[0].width != rt.width || postBufferCache[0].height != rt.height - } else { - false - } - - if (sizeMismatch) { - postBufferCache.forEach { it.destroy() } - postBufferCache.clear() - } - - if (postBufferCache.isEmpty()) { - postBufferCache += colorBuffer(rt.width, rt.height) - postBufferCache += colorBuffer(rt.width, rt.height) - } - } - - val layerPost = postFilters.let { filters -> - val targets = postBufferCache - val result = filters.foldIndexed(target.colorBuffer(0)) { i, source, filter -> - val target = targets[i % targets.size] - filter.first.apply(filter.second) - filter.first.apply(source, target) - target - } - result - } - - val lblend = blendFilter - if (lblend == null) { - drawer.isolatedWithTarget(rt) { - //drawer.ortho(rt) - drawer.ortho() - drawer.view = Matrix44.IDENTITY - drawer.model = Matrix44.IDENTITY - drawer.image(layerPost, layerPost.bounds, drawer.bounds) - } - } else { - lblend.first.apply(lblend.second) - lblend.first.apply(arrayOf(rt.colorBuffer(0), layerPost), rt.colorBuffer(0)) - } - } - } -} - -/** - * create a layer within the composition - */ -fun Layer.layer(function: Layer.() -> Unit) { - children.add(Layer().apply { function() }) -} - -/** - * set the draw contents of the layer - */ -fun Layer.draw(function: () -> Unit) { - drawFunc = function -} - -/** - * add a post-processing filter to the layer - */ -fun Layer.post(filter: F, configure: F.() -> Unit = {}) { - postFilters.add(Pair(filter as Filter, configure as Filter.() -> Unit)) -} - -/** - * add a blend filter to the layer - */ -fun Layer.blend(filter: F, configure: F.() -> Unit = {}) { - blendFilter = Pair(filter as Filter, configure as Filter.() -> Unit) -} - -/** - * create a layered composition - */ -fun compose(function: Layer.() -> Unit): Layer { - val root = Layer() - root.function() - return root +package org.openrndr.extra.compositor + +import org.openrndr.color.ColorRGBa +import org.openrndr.draw.* +import org.openrndr.math.Matrix44 + + +private val postBufferCache = mutableListOf() + +fun RenderTarget.deepDestroy() { + val cbcopy = colorBuffers.map { it} + val dbcopy = depthBuffer + detachDepthBuffer() + detachColorBuffers() + cbcopy.forEach { + it.destroy() + } + dbcopy?.destroy() + destroy() +} + +/** + * A single layer representation + */ +class Layer internal constructor() { + var drawFunc: () -> Unit = {} + val children: MutableList = mutableListOf() + var blendFilter: Pair Unit>? = null + val postFilters: MutableList Unit>> = mutableListOf() + + private var layerTarget:RenderTarget? = null + + /** + * draw the layer + */ + fun draw(drawer: Drawer) { + val rt = RenderTarget.active + + val llt = layerTarget + if (llt == null || (llt.width != rt.width || llt.height != rt.height)) { + layerTarget?.deepDestroy() + layerTarget = renderTarget(rt.width, rt.height) { + colorBuffer() + depthBuffer() + } + } + + layerTarget?.let { target -> + drawer.isolatedWithTarget(target) { + drawer.background(ColorRGBa.TRANSPARENT) + drawFunc() + children.forEach { + it.draw(drawer) + } + } + + if (postFilters.size > 0) { + val sizeMismatch = if (postBufferCache.isNotEmpty()) { + postBufferCache[0].width != rt.width || postBufferCache[0].height != rt.height + } else { + false + } + + if (sizeMismatch) { + postBufferCache.forEach { it.destroy() } + postBufferCache.clear() + } + + if (postBufferCache.isEmpty()) { + postBufferCache += colorBuffer(rt.width, rt.height) + postBufferCache += colorBuffer(rt.width, rt.height) + } + } + + val layerPost = postFilters.let { filters -> + val targets = postBufferCache + val result = filters.foldIndexed(target.colorBuffer(0)) { i, source, filter -> + val target = targets[i % targets.size] + filter.first.apply(filter.second) + filter.first.apply(source, target) + target + } + result + } + + val lblend = blendFilter + if (lblend == null) { + drawer.isolatedWithTarget(rt) { + //drawer.ortho(rt) + drawer.ortho() + drawer.view = Matrix44.IDENTITY + drawer.model = Matrix44.IDENTITY + drawer.image(layerPost, layerPost.bounds, drawer.bounds) + } + } else { + lblend.first.apply(lblend.second) + lblend.first.apply(arrayOf(rt.colorBuffer(0), layerPost), rt.colorBuffer(0)) + } + } + } +} + +/** + * create a layer within the composition + */ +fun Layer.layer(function: Layer.() -> Unit) { + children.add(Layer().apply { function() }) +} + +/** + * set the draw contents of the layer + */ +fun Layer.draw(function: () -> Unit) { + drawFunc = function +} + +/** + * add a post-processing filter to the layer + */ +fun Layer.post(filter: F, configure: F.() -> Unit = {}) { + postFilters.add(Pair(filter as Filter, configure as Filter.() -> Unit)) +} + +/** + * add a blend filter to the layer + */ +fun Layer.blend(filter: F, configure: F.() -> Unit = {}) { + blendFilter = Pair(filter as Filter, configure as Filter.() -> Unit) +} + +/** + * create a layered composition + */ +fun compose(function: Layer.() -> Unit): Layer { + val root = Layer() + root.function() + return root } \ No newline at end of file diff --git a/orx-examples/build.gradle b/orx-examples/build.gradle new file mode 100644 index 000000000..5ddae2504 --- /dev/null +++ b/orx-examples/build.gradle @@ -0,0 +1,31 @@ +plugins { + id 'org.jetbrains.kotlin.jvm' version '1.2.71' +} + +group 'org.openrndr.extra' +version '0.0.1' + +repositories { + mavenCentral() + maven { + url "https://dl.bintray.com/openrndr/openrndr" + } +} + +ext.openrndrVersion = "0.3.26" +ext.orxVersion = "0.0.5" +dependencies { + compile "org.openrndr.extra:orx:0.0.1" + compile "org.openrndr.extra:orx-jumpflood:$orxVersion" + compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8" + compile "org.openrndr:openrndr-core:$openrndrVersion" + runtime "org.openrndr:openrndr-gl3:$openrndrVersion" + runtime "org.openrndr:openrndr-gl3-natives-windows:$openrndrVersion" +} + +compileKotlin { + kotlinOptions.jvmTarget = "1.8" +} +compileTestKotlin { + kotlinOptions.jvmTarget = "1.8" +} \ No newline at end of file diff --git a/orx-examples/gradle/wrapper/gradle-wrapper.jar b/orx-examples/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..1948b9074f1016d15d505d185bc3f73deb82d8c8 GIT binary patch literal 54413 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 \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=$(save "$@") + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong +if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then + cd "$(dirname "$0")" +fi + +exec "$JAVACMD" "$@" diff --git a/orx-examples/gradlew.bat b/orx-examples/gradlew.bat new file mode 100644 index 000000000..e95643d6a --- /dev/null +++ b/orx-examples/gradlew.bat @@ -0,0 +1,84 @@ +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windows variants + +if not "%OS%" == "Windows_NT" goto win9xME_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/orx-examples/settings.gradle b/orx-examples/settings.gradle new file mode 100644 index 000000000..b794b9266 --- /dev/null +++ b/orx-examples/settings.gradle @@ -0,0 +1,2 @@ +rootProject.name = 'orx-examples' + diff --git a/orx-examples/src/main/kotlin/jumpfil-001.kt b/orx-examples/src/main/kotlin/jumpfil-001.kt new file mode 100644 index 000000000..b4e688a91 --- /dev/null +++ b/orx-examples/src/main/kotlin/jumpfil-001.kt @@ -0,0 +1,56 @@ +import org.openrndr.Program +import org.openrndr.application +import org.openrndr.color.ColorRGBa +import org.openrndr.configuration +import org.openrndr.draw.ColorType +import org.openrndr.draw.colorBuffer +import org.openrndr.extra.jumpfill.EncodePoints +import org.openrndr.extra.jumpfill.JumpFlood + +class JumpFill001 : Program() { + + + var drawFunc = {} + override fun setup() { + + val encodePoints = EncodePoints() + val jumpFill = JumpFlood() + + val input = colorBuffer(512, 1024) + val coordinates = + listOf(colorBuffer(input.width, input.height, type = ColorType.FLOAT32), + colorBuffer(input.width, input.height, type = ColorType.FLOAT32)) + + for (i in 0 until 100) { + input.shadow[(Math.random() * input.width).toInt(), (Math.random() * input.height).toInt()] = + ColorRGBa.WHITE + } + input.shadow.upload() + + drawFunc = { + encodePoints.apply(input, coordinates[0]) + drawer.image(coordinates[0]) + jumpFill.maxSteps = 10 + for (i in 0 until 10) { + jumpFill.step = i + jumpFill.apply(coordinates[i % 2], coordinates[(i + 1) % 2]) + } + + drawer.image(coordinates[0]) + + } + } + + override fun draw() { + drawFunc() + } +} + +fun main(args: Array) { + application(JumpFill001(), configuration { + + width = 1024 + height = 1024 + + }) +} \ No newline at end of file diff --git a/orx-examples/src/main/kotlin/jumpfil-002.kt b/orx-examples/src/main/kotlin/jumpfil-002.kt new file mode 100644 index 000000000..0ebd8b754 --- /dev/null +++ b/orx-examples/src/main/kotlin/jumpfil-002.kt @@ -0,0 +1,45 @@ +import org.openrndr.Program +import org.openrndr.application +import org.openrndr.color.ColorRGBa +import org.openrndr.configuration +import org.openrndr.draw.colorBuffer +import org.openrndr.extra.jumpfill.contourPoints +import org.openrndr.extra.jumpfill.jumpFlood +import org.openrndr.extra.jumpfill.threshold + +class JumpFill002 : Program() { + + var drawFunc = {} + override fun setup() { + + val input = colorBuffer(512, 1024) + + for (i in 0 until 3) { + input.shadow[(Math.random() * input.width).toInt(), (Math.random() * input.height).toInt()] = + ColorRGBa.WHITE + } + input.shadow.upload() + + val result = jumpFlood(drawer, input) + +// threshold.apply(result, result) + // contourPoints.apply(result, result) + + drawFunc = { + drawer.image(result) + } + } + + override fun draw() { + drawFunc() + } +} + +fun main(args: Array) { + application(JumpFill002(), configuration { + + width = 1024 + height = 1024 + + }) +} \ No newline at end of file diff --git a/orx-integral-image/src/main/kotlin/FastIntegralImage.kt b/orx-integral-image/src/main/kotlin/FastIntegralImage.kt index feaad8f41..9aed460eb 100644 --- a/orx-integral-image/src/main/kotlin/FastIntegralImage.kt +++ b/orx-integral-image/src/main/kotlin/FastIntegralImage.kt @@ -1,77 +1,77 @@ -package org.openrndr.extra.integralimage - -import org.openrndr.draw.* -import org.openrndr.filter.blend.passthrough -import org.openrndr.math.Vector2 -import org.openrndr.resourceUrl - - -class FastIntegralImageFilter : Filter(filterShaderFromUrl(resourceUrl( - "/shaders/gl3/integral-image.frag" -))) { - var passIndex: Int by parameters - var passDirection: Vector2 by parameters - var sampleCount: Int by parameters - var sampleCountBase: Int by parameters -} - -class FastIntegralImage : Filter(filterShaderFromUrl(resourceUrl( - "/shaders/gl3/integral-image.frag" -))) { - - var intermediate: ColorBuffer? = null - val filter = FastIntegralImageFilter() - - private fun sampleCounts(size:Int, sampleCountBase:Int) : List { - var remainder = size - val sampleCounts = mutableListOf() - while (remainder > 0) { - sampleCounts += if (remainder >= sampleCountBase) { - sampleCountBase - } else { - remainder - } - remainder /= sampleCountBase - } - return sampleCounts - } - - override fun apply(source: Array, target: Array) { - - val sampleCountBase = 16 - val xSampleCounts = sampleCounts(source[0].width, sampleCountBase) - val ySampleCounts = sampleCounts(source[0].height, sampleCountBase) - - val li = intermediate - if (li == null || (li.width != source[0].width || li.height != source[0].height)) { - intermediate?.destroy() - intermediate = colorBuffer(source[0].width, source[0].height, 1.0, ColorFormat.RGBa, ColorType.FLOAT32) - } - - val targets = arrayOf(target, arrayOf(intermediate!!)) - - var targetIndex = 0 - - filter.sampleCountBase = sampleCountBase - - filter.passDirection = Vector2.UNIT_X - for (pass in 0 until xSampleCounts.size) { - filter.sampleCount = xSampleCounts[pass] - filter.passIndex = pass - filter.apply( if (pass == 0) source else targets[targetIndex%2], targets[(targetIndex+1)%2]) - targetIndex++ - } - - filter.passDirection = Vector2.UNIT_Y - for (pass in 0 until ySampleCounts.size) { - filter.sampleCount = ySampleCounts[pass] - filter.passIndex = pass - filter.apply( targets[targetIndex%2], targets[(targetIndex+1)%2]) - targetIndex++ - } - - if (targetIndex%2 == 1) { - passthrough.apply(targets[1], targets[0]) - } - } +package org.openrndr.extra.integralimage + +import org.openrndr.draw.* +import org.openrndr.filter.blend.passthrough +import org.openrndr.math.Vector2 +import org.openrndr.resourceUrl + + +class FastIntegralImageFilter : Filter(filterShaderFromUrl(resourceUrl( + "/shaders/gl3/integral-image.frag" +))) { + var passIndex: Int by parameters + var passDirection: Vector2 by parameters + var sampleCount: Int by parameters + var sampleCountBase: Int by parameters +} + +class FastIntegralImage : Filter(filterShaderFromUrl(resourceUrl( + "/shaders/gl3/integral-image.frag" +))) { + + var intermediate: ColorBuffer? = null + val filter = FastIntegralImageFilter() + + private fun sampleCounts(size:Int, sampleCountBase:Int) : List { + var remainder = size + val sampleCounts = mutableListOf() + while (remainder > 0) { + sampleCounts += if (remainder >= sampleCountBase) { + sampleCountBase + } else { + remainder + } + remainder /= sampleCountBase + } + return sampleCounts + } + + override fun apply(source: Array, target: Array) { + + val sampleCountBase = 16 + val xSampleCounts = sampleCounts(source[0].width, sampleCountBase) + val ySampleCounts = sampleCounts(source[0].height, sampleCountBase) + + val li = intermediate + if (li == null || (li.width != source[0].width || li.height != source[0].height)) { + intermediate?.destroy() + intermediate = colorBuffer(source[0].width, source[0].height, 1.0, ColorFormat.RGBa, ColorType.FLOAT32) + } + + val targets = arrayOf(target, arrayOf(intermediate!!)) + + var targetIndex = 0 + + filter.sampleCountBase = sampleCountBase + + filter.passDirection = Vector2.UNIT_X + for (pass in 0 until xSampleCounts.size) { + filter.sampleCount = xSampleCounts[pass] + filter.passIndex = pass + filter.apply( if (pass == 0) source else targets[targetIndex%2], targets[(targetIndex+1)%2]) + targetIndex++ + } + + filter.passDirection = Vector2.UNIT_Y + for (pass in 0 until ySampleCounts.size) { + filter.sampleCount = ySampleCounts[pass] + filter.passIndex = pass + filter.apply( targets[targetIndex%2], targets[(targetIndex+1)%2]) + targetIndex++ + } + + if (targetIndex%2 == 1) { + passthrough.apply(targets[1], targets[0]) + } + } } \ No newline at end of file diff --git a/orx-integral-image/src/main/resources/shaders/gl3/integral-image.frag b/orx-integral-image/src/main/resources/shaders/gl3/integral-image.frag index 0b3049201..a6dd5bdb6 100644 --- a/orx-integral-image/src/main/resources/shaders/gl3/integral-image.frag +++ b/orx-integral-image/src/main/resources/shaders/gl3/integral-image.frag @@ -1,26 +1,26 @@ -#version 330 core - -uniform sampler2D tex0; -in vec2 v_texCoord0; -out vec4 o_color; - -uniform int passIndex; -uniform int sampleCount; -uniform int sampleCountBase; -uniform vec2 passDirection; - - -void main() { - vec2 passOffset = vec2(pow(sampleCountBase, passIndex)) * (1.0/textureSize(tex0, 0)) * passDirection; - - vec2 uv0 = v_texCoord0; - vec4 result = vec4(0.0); - for (int i = 0; i < sampleCount; ++i) { - vec2 readUV = v_texCoord0 - vec2(i *passOffset); - float factor = step(0.0, readUV.x) * step(0.0, readUV.y); - result += factor * texture(tex0, readUV); - } - - o_color = result; - +#version 330 core + +uniform sampler2D tex0; +in vec2 v_texCoord0; +out vec4 o_color; + +uniform int passIndex; +uniform int sampleCount; +uniform int sampleCountBase; +uniform vec2 passDirection; + + +void main() { + vec2 passOffset = vec2(pow(sampleCountBase, passIndex)) * (1.0/textureSize(tex0, 0)) * passDirection; + + vec2 uv0 = v_texCoord0; + vec4 result = vec4(0.0); + for (int i = 0; i < sampleCount; ++i) { + vec2 readUV = v_texCoord0 - vec2(i *passOffset); + float factor = step(0.0, readUV.x) * step(0.0, readUV.y); + result += factor * texture(tex0, readUV); + } + + o_color = result; + } \ No newline at end of file diff --git a/orx-jumpflood/src/main/kotlin/JumpFlood.kt b/orx-jumpflood/src/main/kotlin/JumpFlood.kt index 41a978f6f..75c2153c1 100644 --- a/orx-jumpflood/src/main/kotlin/JumpFlood.kt +++ b/orx-jumpflood/src/main/kotlin/JumpFlood.kt @@ -1,128 +1,128 @@ -package org.openrndr.extra.jumpfill - -import org.openrndr.color.ColorRGBa -import org.openrndr.draw.* -import org.openrndr.math.Matrix44 -import org.openrndr.math.Vector2 -import org.openrndr.resourceUrl - -class EncodePoints : Filter(filterShaderFromUrl(resourceUrl("/shaders/gl3/encode-points.frag"))) -class JumpFlood : Filter(filterShaderFromUrl(resourceUrl("/shaders/gl3/jumpflood.frag"))) { - var maxSteps: Int by parameters - var step: Int by parameters -} - -class PixelDistance : Filter(filterShaderFromUrl(resourceUrl("/shaders/gl3/pixel-distance.frag"))) -class ContourPoints : Filter(filterShaderFromUrl(resourceUrl("/shaders/gl3/contour-points.frag"))) -class Threshold : Filter(filterShaderFromUrl(resourceUrl("/shaders/gl3/threshold.frag"))) { - var threshold by parameters - - init { - threshold = 0.5 - } -} - -val encodePoints by lazy { EncodePoints() } -val jumpFlood by lazy { JumpFlood() } -val pixelDistance by lazy { PixelDistance() } -val contourPoints by lazy { ContourPoints() } -val threshold by lazy { Threshold() } - - -class JumpFlooder(val width: Int, val height: Int) { - private val dimension = Math.max(width, height) - private val exp = Math.ceil(Math.log(dimension.toDouble()) / Math.log(2.0)).toInt() - private val squareDim = Math.pow(2.0, exp.toDouble()).toInt() - - private val coordinates = - listOf(colorBuffer(squareDim, squareDim, format = ColorFormat.RGB, type = ColorType.FLOAT32), - colorBuffer(squareDim, squareDim, format = ColorFormat.RGB, type = ColorType.FLOAT32)) - - private val final = renderTarget(width, height) { - colorBuffer(type = ColorType.FLOAT32) - } - - val result: ColorBuffer get() = final.colorBuffer(0) - - private val square = renderTarget(squareDim, squareDim) { - colorBuffer() - } - - private var contourUsed = false - private val thresholded by lazy { colorBuffer(width, height) } - private val edges by lazy { colorBuffer(width, height) } - - fun distanceToContour(drawer: Drawer, input: ColorBuffer, thresholdValue: Double = 0.5): ColorBuffer { - threshold.threshold = thresholdValue - threshold.apply(input, thresholded) - contourPoints.apply(thresholded, edges) - contourUsed = true - return jumpFlood(drawer, edges) - } - - fun directions(xRange: IntProgression = 0 until width, yRange: IntProgression = 0 until height): Array> { - result.shadow.download() - return result.shadow.mapIndexed(xRange, yRange) { _, _, r, g, _, _ -> Vector2(r, g) } - } - - - fun jumpFlood(drawer: Drawer, input: ColorBuffer): ColorBuffer { - if (input.width != width || input.height != height) { - throw IllegalArgumentException("dimensions mismatch") - } - - drawer.isolatedWithTarget(square) { - drawer.background(ColorRGBa.BLACK) - drawer.ortho(square) - drawer.view = Matrix44.IDENTITY - drawer.model = Matrix44.IDENTITY - drawer.image(input) - } - encodePoints.apply(square.colorBuffer(0), coordinates[0]) - - for (i in 0 until exp) { - jumpFlood.step = i - jumpFlood.apply(coordinates[i % 2], coordinates[(i + 1) % 2]) - } - - pixelDistance.apply( arrayOf(coordinates[exp % 2], thresholded), coordinates[exp % 2]) - drawer.isolatedWithTarget(final) { - drawer.background(ColorRGBa.BLACK) - drawer.ortho(final) - drawer.view = Matrix44.IDENTITY - drawer.model = Matrix44.IDENTITY - drawer.image(coordinates[exp % 2]) - } - return result - } - - fun destroy(destroyFinal: Boolean = true) { - coordinates.forEach { it.destroy() } - - square.colorBuffer(0).destroy() - square.detachColorBuffers() - square.destroy() - - if (destroyFinal) { - final.colorBuffer(0).destroy() - } - final.detachColorBuffers() - - final.destroy() - - if (contourUsed) { - edges.destroy() - thresholded.destroy() - } - - } - -} - -fun jumpFlood(drawer: Drawer, points: ColorBuffer): ColorBuffer { - val jumpFlooder = JumpFlooder(points.width, points.height) - jumpFlooder.jumpFlood(drawer, points) - val result = jumpFlooder.result - jumpFlooder.destroy(false) - return result +package org.openrndr.extra.jumpfill + +import org.openrndr.color.ColorRGBa +import org.openrndr.draw.* +import org.openrndr.math.Matrix44 +import org.openrndr.math.Vector2 +import org.openrndr.resourceUrl + +class EncodePoints : Filter(filterShaderFromUrl(resourceUrl("/shaders/gl3/encode-points.frag"))) +class JumpFlood : Filter(filterShaderFromUrl(resourceUrl("/shaders/gl3/jumpflood.frag"))) { + var maxSteps: Int by parameters + var step: Int by parameters +} + +class PixelDistance : Filter(filterShaderFromUrl(resourceUrl("/shaders/gl3/pixel-distance.frag"))) +class ContourPoints : Filter(filterShaderFromUrl(resourceUrl("/shaders/gl3/contour-points.frag"))) +class Threshold : Filter(filterShaderFromUrl(resourceUrl("/shaders/gl3/threshold.frag"))) { + var threshold by parameters + + init { + threshold = 0.5 + } +} + +val encodePoints by lazy { EncodePoints() } +val jumpFlood by lazy { JumpFlood() } +val pixelDistance by lazy { PixelDistance() } +val contourPoints by lazy { ContourPoints() } +val threshold by lazy { Threshold() } + + +class JumpFlooder(val width: Int, val height: Int) { + private val dimension = Math.max(width, height) + private val exp = Math.ceil(Math.log(dimension.toDouble()) / Math.log(2.0)).toInt() + private val squareDim = Math.pow(2.0, exp.toDouble()).toInt() + + private val coordinates = + listOf(colorBuffer(squareDim, squareDim, format = ColorFormat.RGB, type = ColorType.FLOAT32), + colorBuffer(squareDim, squareDim, format = ColorFormat.RGB, type = ColorType.FLOAT32)) + + private val final = renderTarget(width, height) { + colorBuffer(type = ColorType.FLOAT32) + } + + val result: ColorBuffer get() = final.colorBuffer(0) + + private val square = renderTarget(squareDim, squareDim) { + colorBuffer() + } + + private var contourUsed = false + val thresholded by lazy { colorBuffer(width, height) } + val edges by lazy { colorBuffer(width, height) } + + fun distanceToContour(drawer: Drawer, input: ColorBuffer, thresholdValue: Double = 0.5): ColorBuffer { + threshold.threshold = thresholdValue + threshold.apply(input, thresholded) + contourPoints.apply(thresholded, edges) + contourUsed = true + return jumpFlood(drawer, edges) + } + + fun directions(xRange: IntProgression = 0 until width, yRange: IntProgression = 0 until height): Array> { + result.shadow.download() + return result.shadow.mapIndexed(xRange, yRange) { _, _, r, g, _, _ -> Vector2(r, g) } + } + + + fun jumpFlood(drawer: Drawer, input: ColorBuffer): ColorBuffer { + if (input.width != width || input.height != height) { + throw IllegalArgumentException("dimensions mismatch") + } + + drawer.isolatedWithTarget(square) { + drawer.background(ColorRGBa.BLACK) + drawer.ortho(square) + drawer.view = Matrix44.IDENTITY + drawer.model = Matrix44.IDENTITY + drawer.image(input) + } + encodePoints.apply(square.colorBuffer(0), coordinates[0]) + + for (i in 0 until exp) { + jumpFlood.step = i + jumpFlood.apply(coordinates[i % 2], coordinates[(i + 1) % 2]) + } + + pixelDistance.apply(arrayOf(coordinates[exp % 2], thresholded), coordinates[exp % 2]) + drawer.isolatedWithTarget(final) { + drawer.background(ColorRGBa.BLACK) + drawer.ortho(final) + drawer.view = Matrix44.IDENTITY + drawer.model = Matrix44.IDENTITY + drawer.image(coordinates[exp % 2]) + } + return result + } + + fun destroy(destroyFinal: Boolean = true) { + coordinates.forEach { it.destroy() } + + square.colorBuffer(0).destroy() + square.detachColorBuffers() + square.destroy() + + if (destroyFinal) { + final.colorBuffer(0).destroy() + } + final.detachColorBuffers() + + final.destroy() + + if (contourUsed) { + edges.destroy() + thresholded.destroy() + } + + } + +} + +fun jumpFlood(drawer: Drawer, points: ColorBuffer): ColorBuffer { + val jumpFlooder = JumpFlooder(points.width, points.height) + jumpFlooder.jumpFlood(drawer, points) + val result = jumpFlooder.result + jumpFlooder.destroy(false) + return result } \ No newline at end of file diff --git a/orx-jumpflood/src/main/resources/shaders/gl3/pixel-distance.frag b/orx-jumpflood/src/main/resources/shaders/gl3/pixel-distance.frag index 2d81a52b5..7eebf70a9 100644 --- a/orx-jumpflood/src/main/resources/shaders/gl3/pixel-distance.frag +++ b/orx-jumpflood/src/main/resources/shaders/gl3/pixel-distance.frag @@ -1,16 +1,16 @@ -#version 330 core - -uniform sampler2D tex0; -uniform sampler2D tex1; -in vec2 v_texCoord0; - -out vec4 o_color; - -void main() { - vec2 size = textureSize(tex0, 0); - vec2 pixelPosition = v_texCoord0; - vec2 centroidPixelPosition = texture(tex0, v_texCoord0).xy; - vec2 pixelDistance = (centroidPixelPosition - pixelPosition) * size * vec2(1.0, -1.0); - float threshold = texture(tex1, v_texCoord0).r; - o_color = vec4(pixelDistance, threshold, 1.0); +#version 330 core + +uniform sampler2D tex0; +uniform sampler2D tex1; +in vec2 v_texCoord0; + +out vec4 o_color; + +void main() { + vec2 size = textureSize(tex0, 0); + vec2 pixelPosition = v_texCoord0; + vec2 centroidPixelPosition = texture(tex0, v_texCoord0).xy; + vec2 pixelDistance = (centroidPixelPosition - pixelPosition) * size * vec2(1.0, -1.0); + float threshold = texture(tex1, v_texCoord0).r; + o_color = vec4(pixelDistance, threshold, 1.0); } \ No newline at end of file diff --git a/orx-mesh-generators/src/main/kotlin/Box.kt b/orx-mesh-generators/src/main/kotlin/Box.kt index 4463ec93c..7be33aefe 100644 --- a/orx-mesh-generators/src/main/kotlin/Box.kt +++ b/orx-mesh-generators/src/main/kotlin/Box.kt @@ -1,61 +1,61 @@ -package org.openrndr.extras.meshgenerators - -import org.openrndr.draw.VertexBuffer -import org.openrndr.math.Vector3 - -fun boxMesh(width: Double = 1.0, height: Double = 1.0, depth: Double = 1.0, - widthSegments: Int = 1, heightSegments: Int = 1, depthSegments: Int = 1, - invert: Boolean = false): VertexBuffer { - val vb = meshVertexBuffer(widthSegments * heightSegments * 6 * 2 + - widthSegments * depthSegments * 6 * 2 + - heightSegments * depthSegments * 6 * 2) - vb.put { - generateBox(width, height, depth, - widthSegments, heightSegments, depthSegments, - invert, bufferWriter(this)) - } - return vb -} - -fun generateBox(width: Double = 1.0, height: Double = 1.0, depth: Double = 1.0, - widthSegments: Int = 1, heightSegments: Int = 1, depthSegments: Int = 1, - invert: Boolean = false, - writer: VertexWriter) { - - val sign = if (invert) -1.0 else 1.0 - // +x -- ZY - generatePlane(Vector3(width / 2.0 * sign, 0.0, 0.0), - Vector3.UNIT_Z, Vector3.UNIT_Y, Vector3.UNIT_X, - -depth, -height, - depthSegments, heightSegments, writer) - - // -x -- ZY - generatePlane(Vector3(-width / 2.0 * sign, 0.0, 0.0), - Vector3.UNIT_Z, Vector3.UNIT_Y, -Vector3.UNIT_X, - -depth, height, - depthSegments, heightSegments, writer) - - // +y -- XZ - generatePlane(Vector3(0.0, height / 2.0 * sign, 0.0), - Vector3.UNIT_X, Vector3.UNIT_Z, Vector3.UNIT_Y, - width, depth, - widthSegments, depthSegments, writer) - - // -y -- XZ - generatePlane(Vector3(0.0, -height / 2.0 * sign, 0.0), - Vector3.UNIT_X, Vector3.UNIT_Z, -Vector3.UNIT_Y, - width, -depth, - widthSegments, depthSegments, writer) - - // +z -- XY - generatePlane(Vector3(0.0, 0.0, depth / 2.0 * sign), - Vector3.UNIT_X, Vector3.UNIT_Y, Vector3.UNIT_Z, - -width, height, - widthSegments, heightSegments, writer) - - // -z -- XY - generatePlane(Vector3(0.0, 0.0, -depth / 2.0 * sign), - Vector3.UNIT_X, Vector3.UNIT_Y, -Vector3.UNIT_Z, - width, height, - widthSegments, heightSegments, writer) +package org.openrndr.extras.meshgenerators + +import org.openrndr.draw.VertexBuffer +import org.openrndr.math.Vector3 + +fun boxMesh(width: Double = 1.0, height: Double = 1.0, depth: Double = 1.0, + widthSegments: Int = 1, heightSegments: Int = 1, depthSegments: Int = 1, + invert: Boolean = false): VertexBuffer { + val vb = meshVertexBuffer(widthSegments * heightSegments * 6 * 2 + + widthSegments * depthSegments * 6 * 2 + + heightSegments * depthSegments * 6 * 2) + vb.put { + generateBox(width, height, depth, + widthSegments, heightSegments, depthSegments, + invert, bufferWriter(this)) + } + return vb +} + +fun generateBox(width: Double = 1.0, height: Double = 1.0, depth: Double = 1.0, + widthSegments: Int = 1, heightSegments: Int = 1, depthSegments: Int = 1, + invert: Boolean = false, + writer: VertexWriter) { + + val sign = if (invert) -1.0 else 1.0 + // +x -- ZY + generatePlane(Vector3(width / 2.0 * sign, 0.0, 0.0), + Vector3.UNIT_Z, Vector3.UNIT_Y, Vector3.UNIT_X, + -depth, -height, + depthSegments, heightSegments, writer) + + // -x -- ZY + generatePlane(Vector3(-width / 2.0 * sign, 0.0, 0.0), + Vector3.UNIT_Z, Vector3.UNIT_Y, -Vector3.UNIT_X, + -depth, height, + depthSegments, heightSegments, writer) + + // +y -- XZ + generatePlane(Vector3(0.0, height / 2.0 * sign, 0.0), + Vector3.UNIT_X, Vector3.UNIT_Z, Vector3.UNIT_Y, + width, depth, + widthSegments, depthSegments, writer) + + // -y -- XZ + generatePlane(Vector3(0.0, -height / 2.0 * sign, 0.0), + Vector3.UNIT_X, Vector3.UNIT_Z, -Vector3.UNIT_Y, + width, -depth, + widthSegments, depthSegments, writer) + + // +z -- XY + generatePlane(Vector3(0.0, 0.0, depth / 2.0 * sign), + Vector3.UNIT_X, Vector3.UNIT_Y, Vector3.UNIT_Z, + -width, height, + widthSegments, heightSegments, writer) + + // -z -- XY + generatePlane(Vector3(0.0, 0.0, -depth / 2.0 * sign), + Vector3.UNIT_X, Vector3.UNIT_Y, -Vector3.UNIT_Z, + width, height, + widthSegments, heightSegments, writer) } \ No newline at end of file diff --git a/orx-mesh-generators/src/main/kotlin/Cap.kt b/orx-mesh-generators/src/main/kotlin/Cap.kt index 26ce263d1..65f7a1162 100644 --- a/orx-mesh-generators/src/main/kotlin/Cap.kt +++ b/orx-mesh-generators/src/main/kotlin/Cap.kt @@ -1,101 +1,101 @@ -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.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) + } + } } \ 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 89d1f2811..c42bf7d70 100644 --- a/orx-mesh-generators/src/main/kotlin/Cylinder.kt +++ b/orx-mesh-generators/src/main/kotlin/Cylinder.kt @@ -1,82 +1,82 @@ -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.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)) + } + } + } } \ 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 4b2b39386..790f44ab0 100644 --- a/orx-mesh-generators/src/main/kotlin/GeneratorBuffer.kt +++ b/orx-mesh-generators/src/main/kotlin/GeneratorBuffer.kt @@ -1,172 +1,172 @@ -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 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 = 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 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-mesh-generators/src/main/kotlin/Plane.kt b/orx-mesh-generators/src/main/kotlin/Plane.kt index 50dbf4b9e..f5b1b0d8e 100644 --- a/orx-mesh-generators/src/main/kotlin/Plane.kt +++ b/orx-mesh-generators/src/main/kotlin/Plane.kt @@ -1,84 +1,84 @@ -package org.openrndr.extras.meshgenerators - -import org.openrndr.draw.VertexBuffer -import org.openrndr.math.Vector2 -import org.openrndr.math.Vector3 - -fun planeMesh(center: Vector3, - right: Vector3, - forward: Vector3, - up: Vector3 = forward.cross(right).normalized, - width: Double = 1.0, height: Double = 1.0, - widthSegments: Int = 1, heightSegments: Int = 1): VertexBuffer { - - val vertexCount = (widthSegments * heightSegments) * 6 - val vb = meshVertexBuffer(vertexCount) - vb.put { - generatePlane(center, right, forward, up, - width, height, widthSegments, heightSegments, bufferWriter(this)) - } - return vb -} - -/** - * generates a finite plane with its center at (0,0,0) and spanning the xz-plane - */ -fun groundPlaneMesh(width: Double = 1.0, - height: Double = 1.0, - widthSegments: Int = 1, - heightSegments: Int = 1): VertexBuffer { - return planeMesh(Vector3.ZERO, Vector3.UNIT_X, Vector3.UNIT_Z, Vector3.UNIT_Y, - width, height, widthSegments, heightSegments) -} - -/** - * generates a finite plane with its center at (0,0,0) and spanning the xy-plane - */ -fun wallPlaneMesh(width: Double = 1.0, - height: Double = 1.0, - widthSegments: Int = 1, - heightSegments: Int = 1): VertexBuffer { - return planeMesh(Vector3.ZERO, Vector3.UNIT_X, Vector3.UNIT_Y, Vector3.UNIT_Z, - width, height, widthSegments, heightSegments) -} - - -fun generatePlane(center: Vector3, - right: Vector3, - forward: Vector3, - up: Vector3 = forward.cross(right).normalized, - - width: Double = 1.0, height: Double = 1.0, - widthSegments: Int = 1, heightSegments: Int = 2, - writer: VertexWriter) { - - val forwardStep = forward.normalized * (height / heightSegments) - val rightStep = right.normalized * (width / widthSegments) - - val corner = center - forward.normalized * (height*0.5) - right.normalized * (width * 0.5) - - val step = Vector2(1.0 / width, 1.0 / height) - - for (v in 0 until heightSegments) { - for (u in 0 until widthSegments) { - - val uv00 = Vector2(u + 0.0, v + 0.0) * step - val uv01 = Vector2(u + 0.0, v + 0.1) * step - val uv10 = Vector2(u + 1.0, v + 0.0) * step - val uv11 = Vector2(u + 1.0, v + 0.1) * step - - val c00 = corner + forwardStep * v.toDouble() + rightStep * u.toDouble() - val c01 = corner + forwardStep * (v + 1).toDouble() + rightStep * u.toDouble() - val c10 = corner + forwardStep * v.toDouble() + rightStep * (u + 1).toDouble() - val c11 = corner + forwardStep * (v + 1).toDouble() + rightStep * (u + 1).toDouble() - - writer(c11, up, uv00) - writer(c10, up, uv10) - writer(c00, up, uv11) - - writer(c00, up, uv11) - writer(c01, up, uv01) - writer(c11, up, uv00) - } - } +package org.openrndr.extras.meshgenerators + +import org.openrndr.draw.VertexBuffer +import org.openrndr.math.Vector2 +import org.openrndr.math.Vector3 + +fun planeMesh(center: Vector3, + right: Vector3, + forward: Vector3, + up: Vector3 = forward.cross(right).normalized, + width: Double = 1.0, height: Double = 1.0, + widthSegments: Int = 1, heightSegments: Int = 1): VertexBuffer { + + val vertexCount = (widthSegments * heightSegments) * 6 + val vb = meshVertexBuffer(vertexCount) + vb.put { + generatePlane(center, right, forward, up, + width, height, widthSegments, heightSegments, bufferWriter(this)) + } + return vb +} + +/** + * generates a finite plane with its center at (0,0,0) and spanning the xz-plane + */ +fun groundPlaneMesh(width: Double = 1.0, + height: Double = 1.0, + widthSegments: Int = 1, + heightSegments: Int = 1): VertexBuffer { + return planeMesh(Vector3.ZERO, Vector3.UNIT_X, Vector3.UNIT_Z, Vector3.UNIT_Y, + width, height, widthSegments, heightSegments) +} + +/** + * generates a finite plane with its center at (0,0,0) and spanning the xy-plane + */ +fun wallPlaneMesh(width: Double = 1.0, + height: Double = 1.0, + widthSegments: Int = 1, + heightSegments: Int = 1): VertexBuffer { + return planeMesh(Vector3.ZERO, Vector3.UNIT_X, Vector3.UNIT_Y, Vector3.UNIT_Z, + width, height, widthSegments, heightSegments) +} + + +fun generatePlane(center: Vector3, + right: Vector3, + forward: Vector3, + up: Vector3 = forward.cross(right).normalized, + + width: Double = 1.0, height: Double = 1.0, + widthSegments: Int = 1, heightSegments: Int = 2, + writer: VertexWriter) { + + val forwardStep = forward.normalized * (height / heightSegments) + val rightStep = right.normalized * (width / widthSegments) + + val corner = center - forward.normalized * (height*0.5) - right.normalized * (width * 0.5) + + val step = Vector2(1.0 / width, 1.0 / height) + + for (v in 0 until heightSegments) { + for (u in 0 until widthSegments) { + + val uv00 = Vector2(u + 0.0, v + 0.0) * step + val uv01 = Vector2(u + 0.0, v + 0.1) * step + val uv10 = Vector2(u + 1.0, v + 0.0) * step + val uv11 = Vector2(u + 1.0, v + 0.1) * step + + val c00 = corner + forwardStep * v.toDouble() + rightStep * u.toDouble() + val c01 = corner + forwardStep * (v + 1).toDouble() + rightStep * u.toDouble() + val c10 = corner + forwardStep * v.toDouble() + rightStep * (u + 1).toDouble() + val c11 = corner + forwardStep * (v + 1).toDouble() + rightStep * (u + 1).toDouble() + + writer(c11, up, uv00) + writer(c10, up, uv10) + writer(c00, up, uv11) + + writer(c00, up, uv11) + writer(c01, up, uv01) + writer(c11, up, uv00) + } + } } \ No newline at end of file diff --git a/orx-mesh-generators/src/main/kotlin/Sphere.kt b/orx-mesh-generators/src/main/kotlin/Sphere.kt index 20ef6f1dc..6f8b577a2 100644 --- a/orx-mesh-generators/src/main/kotlin/Sphere.kt +++ b/orx-mesh-generators/src/main/kotlin/Sphere.kt @@ -1,84 +1,84 @@ -package org.openrndr.extras.meshgenerators - -import org.openrndr.draw.VertexBuffer -import org.openrndr.math.Spherical -import org.openrndr.math.Vector2 - -fun sphereMesh(sides: Int = 16, segments: Int = 16, radius: Double = 1.0, invert: Boolean = false): VertexBuffer { - val vertexCount = 2 * sides * 3 + Math.max(0, (segments - 2)) * sides * 6 - val vb = meshVertexBuffer(vertexCount) - vb.put { - generateSphere(sides, segments, radius, invert, bufferWriter(this)) - } - return vb -} - - -fun generateSphere(sides: Int, segments: Int, radius: Double = 1.0, invert: Boolean = false, writer: VertexWriter) { - val inverter = if (invert) -1.0 else 1.0 - for (t in 0 until segments) { - for (s in 0 until sides) { - val st00 = Spherical(radius, s * Math.PI * 2.0 / sides, t * Math.PI / segments) - val st01 = Spherical(radius, s * Math.PI * 2.0 / sides, (t + 1) * Math.PI / segments) - val st10 = Spherical(radius, (s + 1) * Math.PI * 2.0 / sides, t * Math.PI / segments) - val st11 = Spherical(radius, (s + 1) * Math.PI * 2.0 / sides, (t + 1) * Math.PI / segments) - - val thetaMax = Math.PI - val phiMax = Math.PI * 2.0 - - when (t) { - 0 -> { - writer(st00.cartesian, st00.cartesian.normalized * inverter, Vector2(st00.phi / phiMax, st00.theta / thetaMax)) - writer(st01.cartesian, st01.cartesian.normalized * inverter, Vector2(st01.phi / phiMax, st01.theta / thetaMax)) - writer(st11.cartesian, st11.cartesian.normalized * inverter, Vector2(st11.phi / phiMax, st11.theta / thetaMax)) - } - segments - 1 -> { - writer(st11.cartesian, st11.cartesian.normalized * inverter, Vector2(st11.phi / phiMax, st11.theta / thetaMax)) - writer(st10.cartesian, st10.cartesian.normalized * inverter, Vector2(st10.phi / phiMax, st10.theta / thetaMax)) - writer(st00.cartesian, st00.cartesian.normalized * inverter, Vector2(st00.phi / phiMax, st00.theta / thetaMax)) - } - else -> { - writer(st00.cartesian, st00.cartesian.normalized * inverter, Vector2(st00.phi / phiMax, st00.theta / thetaMax)) - writer(st01.cartesian, st01.cartesian.normalized * inverter, Vector2(st01.phi / phiMax, st01.theta / thetaMax)) - writer(st11.cartesian, st11.cartesian.normalized * inverter, Vector2(st11.phi / phiMax, st11.theta / thetaMax)) - - writer(st11.cartesian, st11.cartesian.normalized * inverter, Vector2(st11.phi / phiMax, st11.theta / thetaMax)) - writer(st10.cartesian, st10.cartesian.normalized * inverter, Vector2(st10.phi / phiMax, st10.theta / thetaMax)) - writer(st00.cartesian, st00.cartesian.normalized * inverter, Vector2(st00.phi / phiMax, st00.theta / thetaMax)) - } - } - } - } -} - -fun generateHemisphere(sides: Int, segments: Int, radius: Double = 1.0, invert: Boolean = false, writer: VertexWriter) { - val inverter = if (invert) -1.0 else 1.0 - for (t in 0 until segments) { - for (s in 0 until sides) { - val st00 = Spherical(radius, s * Math.PI * 2.0 / sides, t * Math.PI*0.5 / segments) - val st01 = Spherical(radius, s * Math.PI * 2.0 / sides, (t + 1) * Math.PI*0.5 / segments) - val st10 = Spherical(radius, (s + 1) * Math.PI * 2.0 / sides, t * Math.PI*0.5 / segments) - val st11 = Spherical(radius, (s + 1) * Math.PI * 2.0 / sides, (t + 1) * Math.PI*0.5 / segments) - - val thetaMax = Math.PI * 0.5 - val phiMax = Math.PI * 2.0 - - when (t) { - 0 -> { - writer(st00.cartesian, st00.cartesian.normalized * inverter, Vector2(st00.phi / phiMax, st00.theta / thetaMax)) - writer(st01.cartesian, st01.cartesian.normalized * inverter, Vector2(st01.phi / phiMax, st01.theta / thetaMax)) - writer(st11.cartesian, st11.cartesian.normalized * inverter, Vector2(st11.phi / phiMax, st11.theta / thetaMax)) - } - else -> { - writer(st00.cartesian, st00.cartesian.normalized * inverter, Vector2(st00.phi / phiMax, st00.theta / thetaMax)) - writer(st01.cartesian, st01.cartesian.normalized * inverter, Vector2(st01.phi / phiMax, st01.theta / thetaMax)) - writer(st11.cartesian, st11.cartesian.normalized * inverter, Vector2(st11.phi / phiMax, st11.theta / thetaMax)) - - writer(st11.cartesian, st11.cartesian.normalized * inverter, Vector2(st11.phi / phiMax, st11.theta / thetaMax)) - writer(st10.cartesian, st10.cartesian.normalized * inverter, Vector2(st10.phi / phiMax, st10.theta / thetaMax)) - writer(st00.cartesian, st00.cartesian.normalized * inverter, Vector2(st00.phi / phiMax, st00.theta / thetaMax)) - } - } - } - } +package org.openrndr.extras.meshgenerators + +import org.openrndr.draw.VertexBuffer +import org.openrndr.math.Spherical +import org.openrndr.math.Vector2 + +fun sphereMesh(sides: Int = 16, segments: Int = 16, radius: Double = 1.0, invert: Boolean = false): VertexBuffer { + val vertexCount = 2 * sides * 3 + Math.max(0, (segments - 2)) * sides * 6 + val vb = meshVertexBuffer(vertexCount) + vb.put { + generateSphere(sides, segments, radius, invert, bufferWriter(this)) + } + return vb +} + + +fun generateSphere(sides: Int, segments: Int, radius: Double = 1.0, invert: Boolean = false, writer: VertexWriter) { + val inverter = if (invert) -1.0 else 1.0 + for (t in 0 until segments) { + for (s in 0 until sides) { + val st00 = Spherical(radius, s * Math.PI * 2.0 / sides, t * Math.PI / segments) + val st01 = Spherical(radius, s * Math.PI * 2.0 / sides, (t + 1) * Math.PI / segments) + val st10 = Spherical(radius, (s + 1) * Math.PI * 2.0 / sides, t * Math.PI / segments) + val st11 = Spherical(radius, (s + 1) * Math.PI * 2.0 / sides, (t + 1) * Math.PI / segments) + + val thetaMax = Math.PI + val phiMax = Math.PI * 2.0 + + when (t) { + 0 -> { + writer(st00.cartesian, st00.cartesian.normalized * inverter, Vector2(st00.phi / phiMax, st00.theta / thetaMax)) + writer(st01.cartesian, st01.cartesian.normalized * inverter, Vector2(st01.phi / phiMax, st01.theta / thetaMax)) + writer(st11.cartesian, st11.cartesian.normalized * inverter, Vector2(st11.phi / phiMax, st11.theta / thetaMax)) + } + segments - 1 -> { + writer(st11.cartesian, st11.cartesian.normalized * inverter, Vector2(st11.phi / phiMax, st11.theta / thetaMax)) + writer(st10.cartesian, st10.cartesian.normalized * inverter, Vector2(st10.phi / phiMax, st10.theta / thetaMax)) + writer(st00.cartesian, st00.cartesian.normalized * inverter, Vector2(st00.phi / phiMax, st00.theta / thetaMax)) + } + else -> { + writer(st00.cartesian, st00.cartesian.normalized * inverter, Vector2(st00.phi / phiMax, st00.theta / thetaMax)) + writer(st01.cartesian, st01.cartesian.normalized * inverter, Vector2(st01.phi / phiMax, st01.theta / thetaMax)) + writer(st11.cartesian, st11.cartesian.normalized * inverter, Vector2(st11.phi / phiMax, st11.theta / thetaMax)) + + writer(st11.cartesian, st11.cartesian.normalized * inverter, Vector2(st11.phi / phiMax, st11.theta / thetaMax)) + writer(st10.cartesian, st10.cartesian.normalized * inverter, Vector2(st10.phi / phiMax, st10.theta / thetaMax)) + writer(st00.cartesian, st00.cartesian.normalized * inverter, Vector2(st00.phi / phiMax, st00.theta / thetaMax)) + } + } + } + } +} + +fun generateHemisphere(sides: Int, segments: Int, radius: Double = 1.0, invert: Boolean = false, writer: VertexWriter) { + val inverter = if (invert) -1.0 else 1.0 + for (t in 0 until segments) { + for (s in 0 until sides) { + val st00 = Spherical(radius, s * Math.PI * 2.0 / sides, t * Math.PI*0.5 / segments) + val st01 = Spherical(radius, s * Math.PI * 2.0 / sides, (t + 1) * Math.PI*0.5 / segments) + val st10 = Spherical(radius, (s + 1) * Math.PI * 2.0 / sides, t * Math.PI*0.5 / segments) + val st11 = Spherical(radius, (s + 1) * Math.PI * 2.0 / sides, (t + 1) * Math.PI*0.5 / segments) + + val thetaMax = Math.PI * 0.5 + val phiMax = Math.PI * 2.0 + + when (t) { + 0 -> { + writer(st00.cartesian, st00.cartesian.normalized * inverter, Vector2(st00.phi / phiMax, st00.theta / thetaMax)) + writer(st01.cartesian, st01.cartesian.normalized * inverter, Vector2(st01.phi / phiMax, st01.theta / thetaMax)) + writer(st11.cartesian, st11.cartesian.normalized * inverter, Vector2(st11.phi / phiMax, st11.theta / thetaMax)) + } + else -> { + writer(st00.cartesian, st00.cartesian.normalized * inverter, Vector2(st00.phi / phiMax, st00.theta / thetaMax)) + writer(st01.cartesian, st01.cartesian.normalized * inverter, Vector2(st01.phi / phiMax, st01.theta / thetaMax)) + writer(st11.cartesian, st11.cartesian.normalized * inverter, Vector2(st11.phi / phiMax, st11.theta / thetaMax)) + + writer(st11.cartesian, st11.cartesian.normalized * inverter, Vector2(st11.phi / phiMax, st11.theta / thetaMax)) + writer(st10.cartesian, st10.cartesian.normalized * inverter, Vector2(st10.phi / phiMax, st10.theta / thetaMax)) + writer(st00.cartesian, st00.cartesian.normalized * inverter, Vector2(st00.phi / phiMax, st00.theta / thetaMax)) + } + } + } + } } \ No newline at end of file diff --git a/orx-no-clear/README.md b/orx-no-clear/README.md index 6de33c339..4f435d5ea 100644 --- a/orx-no-clear/README.md +++ b/orx-no-clear/README.md @@ -1,54 +1,54 @@ -# orx-no-clear - -A simple OPENRNDR Extension that provides the classical drawing-without-clearing-the-screen functionality that -OPENRNDR does not support natively. - -#### Usage - -```kotlin -fun main() = application { - configure { - title = "NoClearProgram" - } - program { - backgroundColor = ColorRGBa.PINK - extend(NoClear()) - extend { - drawer.circle(Math.cos(seconds) * width / 2.0 + width / 2.0, Math.sin(seconds * 0.24) * height / 2.0 + height / 2.0, 20.0) - } - } -} -``` - -#### Usage with additional configuration -Optionally, a static `backdrop` may be setup by providing custom code. - -- Example 1. Customising the backdrop with an image -```kotlin -extend(NoClear()) { - val img = loadImage("data\\backdrop.png") - backdrop = { - drawer.image(img, 0.0, 0.0, width * 1.0, height * 1.0) - } -} -``` - -- Example 2. Customising the backdrop with a checker-board pattern -```kotlin -extend(NoClear()) { - backdrop = { - val xw = width / 8.0 - val yh = height / 8.0 - drawer.fill = ColorRGBa.RED - (0..7).forEach { row -> - (0..7).forEach { col -> - if ((row + col) % 2 == 0) { - drawer.rectangle(row * xw, col * yh, xw, yh) - } - } - } - } -} -``` - +# orx-no-clear + +A simple OPENRNDR Extension that provides the classical drawing-without-clearing-the-screen functionality that +OPENRNDR does not support natively. + +#### Usage + +```kotlin +fun main() = application { + configure { + title = "NoClearProgram" + } + program { + backgroundColor = ColorRGBa.PINK + extend(NoClear()) + extend { + drawer.circle(Math.cos(seconds) * width / 2.0 + width / 2.0, Math.sin(seconds * 0.24) * height / 2.0 + height / 2.0, 20.0) + } + } +} +``` + +#### Usage with additional configuration +Optionally, a static `backdrop` may be setup by providing custom code. + +- Example 1. Customising the backdrop with an image +```kotlin +extend(NoClear()) { + val img = loadImage("data\\backdrop.png") + backdrop = { + drawer.image(img, 0.0, 0.0, width * 1.0, height * 1.0) + } +} +``` + +- Example 2. Customising the backdrop with a checker-board pattern +```kotlin +extend(NoClear()) { + backdrop = { + val xw = width / 8.0 + val yh = height / 8.0 + drawer.fill = ColorRGBa.RED + (0..7).forEach { row -> + (0..7).forEach { col -> + if ((row + col) % 2 == 0) { + drawer.rectangle(row * xw, col * yh, xw, yh) + } + } + } + } +} +``` + NB! any submitted _lambda expression_ must be valid within the `renderTarget` context. \ No newline at end of file diff --git a/orx-no-clear/src/main/kotlin/NoClear.kt b/orx-no-clear/src/main/kotlin/NoClear.kt index 9a1872826..b68d5283e 100644 --- a/orx-no-clear/src/main/kotlin/NoClear.kt +++ b/orx-no-clear/src/main/kotlin/NoClear.kt @@ -1,57 +1,57 @@ -package org.openrndr.extra.noclear - -import org.openrndr.Extension -import org.openrndr.Program -import org.openrndr.color.ColorRGBa -import org.openrndr.draw.Drawer -import org.openrndr.draw.RenderTarget -import org.openrndr.draw.isolated -import org.openrndr.draw.renderTarget -import org.openrndr.math.Matrix44 - -class NoClear : Extension { - override var enabled: Boolean = true - private var renderTarget: RenderTarget? = null - - /** - * code-block to draw an optional custom backdrop - */ - var backdrop: (() -> Unit)? = null - - override fun beforeDraw(drawer: Drawer, program: Program) { - if (program.width > 0 && program.height > 0) { // only if the window is not minimised - if (renderTarget == null || renderTarget?.width != program.width || renderTarget?.height != program.height) { - renderTarget?.let { - it.colorBuffer(0).destroy() - it.detachColorBuffers() - it.destroy() - } - renderTarget = renderTarget(program.width, program.height) { - colorBuffer() - depthBuffer() - } - - renderTarget?.let { - drawer.withTarget(it) { - background(program.backgroundColor ?: ColorRGBa.TRANSPARENT) - backdrop?.invoke() // draw custom backdrop - } - } - } - } - renderTarget?.bind() - } - - override fun afterDraw(drawer: Drawer, program: Program) { - renderTarget?.unbind() - - renderTarget?.let { - drawer.isolated { - drawer.ortho() - drawer.view = Matrix44.IDENTITY - drawer.model = Matrix44.IDENTITY - drawer.image(it.colorBuffer(0)) - } - } - } +package org.openrndr.extra.noclear + +import org.openrndr.Extension +import org.openrndr.Program +import org.openrndr.color.ColorRGBa +import org.openrndr.draw.Drawer +import org.openrndr.draw.RenderTarget +import org.openrndr.draw.isolated +import org.openrndr.draw.renderTarget +import org.openrndr.math.Matrix44 + +class NoClear : Extension { + override var enabled: Boolean = true + private var renderTarget: RenderTarget? = null + + /** + * code-block to draw an optional custom backdrop + */ + var backdrop: (() -> Unit)? = null + + override fun beforeDraw(drawer: Drawer, program: Program) { + if (program.width > 0 && program.height > 0) { // only if the window is not minimised + if (renderTarget == null || renderTarget?.width != program.width || renderTarget?.height != program.height) { + renderTarget?.let { + it.colorBuffer(0).destroy() + it.detachColorBuffers() + it.destroy() + } + renderTarget = renderTarget(program.width, program.height) { + colorBuffer() + depthBuffer() + } + + renderTarget?.let { + drawer.withTarget(it) { + background(program.backgroundColor ?: ColorRGBa.TRANSPARENT) + backdrop?.invoke() // draw custom backdrop + } + } + } + } + renderTarget?.bind() + } + + override fun afterDraw(drawer: Drawer, program: Program) { + renderTarget?.unbind() + + renderTarget?.let { + drawer.isolated { + drawer.ortho() + drawer.view = Matrix44.IDENTITY + drawer.model = Matrix44.IDENTITY + drawer.image(it.colorBuffer(0)) + } + } + } } \ No newline at end of file diff --git a/orx-noise/README.md b/orx-noise/README.md index 7fe04b105..59d285640 100644 --- a/orx-noise/README.md +++ b/orx-noise/README.md @@ -1,123 +1,123 @@ -# orx-noise - -A collection of noisy functions - -## Uniform random numbers - -```kotlin -val sua = Double.uniform() -val sub = Double.uniform(-1.0, 1.0) - -val v2ua = Vector2.uniform() -val v2ub = Vector2.uniform(-1.0, 1.0) -val v2uc = Vector2.uniform(Vector2(0.0, 0.0), Vector2(1.0, 1.0)) -val v2ur = Vector2.uniformRing(0.5, 1.0) - -val v3ua = Vector3.uniform() -val v3ub = Vector3.uniform(-1.0, 1.0) -val v3uc = Vector3.uniform(Vector3(0.0, 0.0, 0.0), Vector3(1.0, 1.0, 1.0)) -val v3ur = Vector3.uniformRing(0.5, 1.0) - -val v4ua = Vector4.uniform() -val v4ub = Vector4.uniform(-1.0, 1.0) -val v4uc = Vector4.uniform(Vector4(0.0, 0.0, 0.0, 0.0), Vector4(1.0, 1.0, 1.0, 1.0)) -val v4ur = Vector4.uniformRing(0.5, 1.0) - -val ringSamples = List(500) { Vector2.uniformRing() } -``` - -## Multi-dimensional noise - -These are a mostly straight port from FastNoise-Java but have a slightly different interface. - -### Perlin noise -``` -// -- 2d -val v0 = perlinLinear(seed, x, y) -val v1 = perlinQuintic(seed, x, y) -val v2 = perlinHermite(seed, x, y) - -// -- 3d -val v3 = perlinLinear(seed, x, y, z) -val v4 = perlinQuintic(seed, x, y, z) -val v5 = perlinHermite(seed, x, y, z) -``` - -### Value noise -``` -// -- 2d -val v0 = valueLinear(seed, x, y) -val v1 = valueQuintic(seed, x, y) -val v2 = valueHermite(seed, x, y) - -// -- 3d -val v3 = valueLinear(seed, x, y, z) -val v4 = valueQuintic(seed, x, y, z) -val v5 = valueHermite(seed, x, y ,z) -``` - -### Simplex noise -``` -// -- 2d -val v0 = simplexLinear(seed, x, y) -val v1 = simplexQuintic(seed, x, y) -val v2 = simplexHermite(seed, x, y) - -// -- 3d -val v3 = simplexLinear(seed, x, y, z) -val v4 = simplexQuintic(seed, x, y, z) -val v5 = simplexHermite(seed, x, y ,z) -``` - -### Cubic noise -``` -// -- 2d -val v0 = cubicLinear(seed, x, y) -val v1 = cubicQuintic(seed, x, y) -val v2 = cubicHermite(seed, x, y) - -// -- 3d -val v3 = cubicLinear(seed, x, y, z) -val v4 = cubicQuintic(seed, x, y, z) -val v5 = cubicHermite(seed, x, y ,z) -``` - -### Fractal noise - -The library provides 3 functions with which fractal noise can be composed. - -#### Fractal brownian motion (FBM) - -``` -val v0 = fbm(seed, x, y, ::perlinLinear, octaves, lacunarity, gain) -val v1 = fbm(seed, x, y, ::simplexLinear, octaves, lacunarity, gain) -val v2 = fbm(seed, x, y, ::valueLinear, octaves, lacunarity, gain) - -val v3 = fbm(seed, x, y, z, ::perlinLinear, octaves, lacunarity, gain) -val v4 = fbm(seed, x, y, z, ::simplexLinear, octaves, lacunarity, gain) -val v5 = fbm(seed, x, y, z, ::valueLinear, octaves, lacunarity, gain) -``` - -#### Rigid - -``` -val v0 = rigid(seed, x, y, ::perlinLinear, octaves, lacunarity, gain) -val v1 = rigid(seed, x, y, ::simplexLinear, octaves, lacunarity, gain) -val v2 = rigid(seed, x, y, ::valueLinear, octaves, lacunarity, gain) - -val v3 = rigid(seed, x, y, z, ::perlinLinear, octaves, lacunarity, gain) -val v4 = rigid(seed, x, y, z, ::simplexLinear, octaves, lacunarity, gain) -val v5 = rigid(seed, x, y, z, ::valueLinear, octaves, lacunarity, gain) -``` - -#### Billow - -``` -val v0 = billow(seed, x, y, ::perlinLinear, octaves, lacunarity, gain) -val v1 = billow(seed, x, y, ::perlinLinear, octaves, lacunarity, gain) -val v2 = billow(seed, x, y, ::perlinLinear, octaves, lacunarity, gain) - -val v3 = billow(seed, x, y, z, ::perlinLinear, octaves, lacunarity, gain) -val v4 = billow(seed, x, y, z, ::perlinLinear, octaves, lacunarity, gain) -val v5 = billow(seed, x, y, z, ::perlinLinear, octaves, lacunarity, gain) +# orx-noise + +A collection of noisy functions + +## Uniform random numbers + +```kotlin +val sua = Double.uniform() +val sub = Double.uniform(-1.0, 1.0) + +val v2ua = Vector2.uniform() +val v2ub = Vector2.uniform(-1.0, 1.0) +val v2uc = Vector2.uniform(Vector2(0.0, 0.0), Vector2(1.0, 1.0)) +val v2ur = Vector2.uniformRing(0.5, 1.0) + +val v3ua = Vector3.uniform() +val v3ub = Vector3.uniform(-1.0, 1.0) +val v3uc = Vector3.uniform(Vector3(0.0, 0.0, 0.0), Vector3(1.0, 1.0, 1.0)) +val v3ur = Vector3.uniformRing(0.5, 1.0) + +val v4ua = Vector4.uniform() +val v4ub = Vector4.uniform(-1.0, 1.0) +val v4uc = Vector4.uniform(Vector4(0.0, 0.0, 0.0, 0.0), Vector4(1.0, 1.0, 1.0, 1.0)) +val v4ur = Vector4.uniformRing(0.5, 1.0) + +val ringSamples = List(500) { Vector2.uniformRing() } +``` + +## Multi-dimensional noise + +These are a mostly straight port from FastNoise-Java but have a slightly different interface. + +### Perlin noise +``` +// -- 2d +val v0 = perlinLinear(seed, x, y) +val v1 = perlinQuintic(seed, x, y) +val v2 = perlinHermite(seed, x, y) + +// -- 3d +val v3 = perlinLinear(seed, x, y, z) +val v4 = perlinQuintic(seed, x, y, z) +val v5 = perlinHermite(seed, x, y, z) +``` + +### Value noise +``` +// -- 2d +val v0 = valueLinear(seed, x, y) +val v1 = valueQuintic(seed, x, y) +val v2 = valueHermite(seed, x, y) + +// -- 3d +val v3 = valueLinear(seed, x, y, z) +val v4 = valueQuintic(seed, x, y, z) +val v5 = valueHermite(seed, x, y ,z) +``` + +### Simplex noise +``` +// -- 2d +val v0 = simplexLinear(seed, x, y) +val v1 = simplexQuintic(seed, x, y) +val v2 = simplexHermite(seed, x, y) + +// -- 3d +val v3 = simplexLinear(seed, x, y, z) +val v4 = simplexQuintic(seed, x, y, z) +val v5 = simplexHermite(seed, x, y ,z) +``` + +### Cubic noise +``` +// -- 2d +val v0 = cubicLinear(seed, x, y) +val v1 = cubicQuintic(seed, x, y) +val v2 = cubicHermite(seed, x, y) + +// -- 3d +val v3 = cubicLinear(seed, x, y, z) +val v4 = cubicQuintic(seed, x, y, z) +val v5 = cubicHermite(seed, x, y ,z) +``` + +### Fractal noise + +The library provides 3 functions with which fractal noise can be composed. + +#### Fractal brownian motion (FBM) + +``` +val v0 = fbm(seed, x, y, ::perlinLinear, octaves, lacunarity, gain) +val v1 = fbm(seed, x, y, ::simplexLinear, octaves, lacunarity, gain) +val v2 = fbm(seed, x, y, ::valueLinear, octaves, lacunarity, gain) + +val v3 = fbm(seed, x, y, z, ::perlinLinear, octaves, lacunarity, gain) +val v4 = fbm(seed, x, y, z, ::simplexLinear, octaves, lacunarity, gain) +val v5 = fbm(seed, x, y, z, ::valueLinear, octaves, lacunarity, gain) +``` + +#### Rigid + +``` +val v0 = rigid(seed, x, y, ::perlinLinear, octaves, lacunarity, gain) +val v1 = rigid(seed, x, y, ::simplexLinear, octaves, lacunarity, gain) +val v2 = rigid(seed, x, y, ::valueLinear, octaves, lacunarity, gain) + +val v3 = rigid(seed, x, y, z, ::perlinLinear, octaves, lacunarity, gain) +val v4 = rigid(seed, x, y, z, ::simplexLinear, octaves, lacunarity, gain) +val v5 = rigid(seed, x, y, z, ::valueLinear, octaves, lacunarity, gain) +``` + +#### Billow + +``` +val v0 = billow(seed, x, y, ::perlinLinear, octaves, lacunarity, gain) +val v1 = billow(seed, x, y, ::perlinLinear, octaves, lacunarity, gain) +val v2 = billow(seed, x, y, ::perlinLinear, octaves, lacunarity, gain) + +val v3 = billow(seed, x, y, z, ::perlinLinear, octaves, lacunarity, gain) +val v4 = billow(seed, x, y, z, ::perlinLinear, octaves, lacunarity, gain) +val v5 = billow(seed, x, y, z, ::perlinLinear, octaves, lacunarity, gain) ``` \ No newline at end of file diff --git a/orx-noise/src/main/kotlin/CubicNoise2D.kt b/orx-noise/src/main/kotlin/CubicNoise2D.kt index f20299cc1..afcb1b427 100644 --- a/orx-noise/src/main/kotlin/CubicNoise2D.kt +++ b/orx-noise/src/main/kotlin/CubicNoise2D.kt @@ -1,28 +1,28 @@ -package org.openrndr.extra.noise - -private const val CUBIC_2D_BOUNDING = 1 / (1.5 * 1.5).toFloat() -fun cubic(seed: Int, x: Double, y: Double): Double { - val x1 = x.fastFloor() - val y1 = y.fastFloor() - - val x0 = x1 - 1 - val y0 = y1 - 1 - val x2 = x1 + 1 - val y2 = y1 + 1 - val x3 = x1 + 2 - val y3 = y1 + 2 - - val xs = x - x1.toDouble() - val ys = y - y1.toDouble() - - return cubic( - cubic(valCoord2D(seed, x0, y0), valCoord2D(seed, x1, y0), valCoord2D(seed, x2, y0), valCoord2D(seed, x3, y0), - xs), - cubic(valCoord2D(seed, x0, y1), valCoord2D(seed, x1, y1), valCoord2D(seed, x2, y1), valCoord2D(seed, x3, y1), - xs), - cubic(valCoord2D(seed, x0, y2), valCoord2D(seed, x1, y2), valCoord2D(seed, x2, y2), valCoord2D(seed, x3, y2), - xs), - cubic(valCoord2D(seed, x0, y3), valCoord2D(seed, x1, y3), valCoord2D(seed, x2, y3), valCoord2D(seed, x3, y3), - xs), - ys) * CUBIC_2D_BOUNDING +package org.openrndr.extra.noise + +private const val CUBIC_2D_BOUNDING = 1 / (1.5 * 1.5).toFloat() +fun cubic(seed: Int, x: Double, y: Double): Double { + val x1 = x.fastFloor() + val y1 = y.fastFloor() + + val x0 = x1 - 1 + val y0 = y1 - 1 + val x2 = x1 + 1 + val y2 = y1 + 1 + val x3 = x1 + 2 + val y3 = y1 + 2 + + val xs = x - x1.toDouble() + val ys = y - y1.toDouble() + + return cubic( + cubic(valCoord2D(seed, x0, y0), valCoord2D(seed, x1, y0), valCoord2D(seed, x2, y0), valCoord2D(seed, x3, y0), + xs), + cubic(valCoord2D(seed, x0, y1), valCoord2D(seed, x1, y1), valCoord2D(seed, x2, y1), valCoord2D(seed, x3, y1), + xs), + cubic(valCoord2D(seed, x0, y2), valCoord2D(seed, x1, y2), valCoord2D(seed, x2, y2), valCoord2D(seed, x3, y2), + xs), + cubic(valCoord2D(seed, x0, y3), valCoord2D(seed, x1, y3), valCoord2D(seed, x2, y3), valCoord2D(seed, x3, y3), + xs), + ys) * CUBIC_2D_BOUNDING } \ No newline at end of file diff --git a/orx-noise/src/main/kotlin/CubicNoise3D.kt b/orx-noise/src/main/kotlin/CubicNoise3D.kt index 584b75874..de22f689e 100644 --- a/orx-noise/src/main/kotlin/CubicNoise3D.kt +++ b/orx-noise/src/main/kotlin/CubicNoise3D.kt @@ -1,51 +1,51 @@ -package org.openrndr.extra.noise - - -private const val CUBIC_3D_BOUNDING = 1 / (1.5 * 1.5 * 1.5).toFloat() - -fun cubic(seed: Int, x: Double, y: Double, z: Double): Double { - val x1 = x.fastFloor() - val y1 = y.fastFloor() - val z1 = z.fastFloor() - - val x0 = x1 - 1 - val y0 = y1 - 1 - val z0 = z1 - 1 - val x2 = x1 + 1 - val y2 = y1 + 1 - val z2 = z1 + 1 - val x3 = x1 + 2 - val y3 = y1 + 2 - val z3 = z1 + 2 - - val xs = x - x1.toFloat() - val ys = y - y1.toFloat() - val zs = z - z1.toFloat() - - return cubic( - cubic( - cubic(valCoord3D(seed, x0, y0, z0), valCoord3D(seed, x1, y0, z0), valCoord3D(seed, x2, y0, z0), valCoord3D(seed, x3, y0, z0), xs), - cubic(valCoord3D(seed, x0, y1, z0), valCoord3D(seed, x1, y1, z0), valCoord3D(seed, x2, y1, z0), valCoord3D(seed, x3, y1, z0), xs), - cubic(valCoord3D(seed, x0, y2, z0), valCoord3D(seed, x1, y2, z0), valCoord3D(seed, x2, y2, z0), valCoord3D(seed, x3, y2, z0), xs), - cubic(valCoord3D(seed, x0, y3, z0), valCoord3D(seed, x1, y3, z0), valCoord3D(seed, x2, y3, z0), valCoord3D(seed, x3, y3, z0), xs), - ys), - cubic( - cubic(valCoord3D(seed, x0, y0, z1), valCoord3D(seed, x1, y0, z1), valCoord3D(seed, x2, y0, z1), valCoord3D(seed, x3, y0, z1), xs), - cubic(valCoord3D(seed, x0, y1, z1), valCoord3D(seed, x1, y1, z1), valCoord3D(seed, x2, y1, z1), valCoord3D(seed, x3, y1, z1), xs), - cubic(valCoord3D(seed, x0, y2, z1), valCoord3D(seed, x1, y2, z1), valCoord3D(seed, x2, y2, z1), valCoord3D(seed, x3, y2, z1), xs), - cubic(valCoord3D(seed, x0, y3, z1), valCoord3D(seed, x1, y3, z1), valCoord3D(seed, x2, y3, z1), valCoord3D(seed, x3, y3, z1), xs), - ys), - cubic( - cubic(valCoord3D(seed, x0, y0, z2), valCoord3D(seed, x1, y0, z2), valCoord3D(seed, x2, y0, z2), valCoord3D(seed, x3, y0, z2), xs), - cubic(valCoord3D(seed, x0, y1, z2), valCoord3D(seed, x1, y1, z2), valCoord3D(seed, x2, y1, z2), valCoord3D(seed, x3, y1, z2), xs), - cubic(valCoord3D(seed, x0, y2, z2), valCoord3D(seed, x1, y2, z2), valCoord3D(seed, x2, y2, z2), valCoord3D(seed, x3, y2, z2), xs), - cubic(valCoord3D(seed, x0, y3, z2), valCoord3D(seed, x1, y3, z2), valCoord3D(seed, x2, y3, z2), valCoord3D(seed, x3, y3, z2), xs), - ys), - cubic( - cubic(valCoord3D(seed, x0, y0, z3), valCoord3D(seed, x1, y0, z3), valCoord3D(seed, x2, y0, z3), valCoord3D(seed, x3, y0, z3), xs), - cubic(valCoord3D(seed, x0, y1, z3), valCoord3D(seed, x1, y1, z3), valCoord3D(seed, x2, y1, z3), valCoord3D(seed, x3, y1, z3), xs), - cubic(valCoord3D(seed, x0, y2, z3), valCoord3D(seed, x1, y2, z3), valCoord3D(seed, x2, y2, z3), valCoord3D(seed, x3, y2, z3), xs), - cubic(valCoord3D(seed, x0, y3, z3), valCoord3D(seed, x1, y3, z3), valCoord3D(seed, x2, y3, z3), valCoord3D(seed, x3, y3, z3), xs), - ys), - zs) * CUBIC_3D_BOUNDING +package org.openrndr.extra.noise + + +private const val CUBIC_3D_BOUNDING = 1 / (1.5 * 1.5 * 1.5).toFloat() + +fun cubic(seed: Int, x: Double, y: Double, z: Double): Double { + val x1 = x.fastFloor() + val y1 = y.fastFloor() + val z1 = z.fastFloor() + + val x0 = x1 - 1 + val y0 = y1 - 1 + val z0 = z1 - 1 + val x2 = x1 + 1 + val y2 = y1 + 1 + val z2 = z1 + 1 + val x3 = x1 + 2 + val y3 = y1 + 2 + val z3 = z1 + 2 + + val xs = x - x1.toFloat() + val ys = y - y1.toFloat() + val zs = z - z1.toFloat() + + return cubic( + cubic( + cubic(valCoord3D(seed, x0, y0, z0), valCoord3D(seed, x1, y0, z0), valCoord3D(seed, x2, y0, z0), valCoord3D(seed, x3, y0, z0), xs), + cubic(valCoord3D(seed, x0, y1, z0), valCoord3D(seed, x1, y1, z0), valCoord3D(seed, x2, y1, z0), valCoord3D(seed, x3, y1, z0), xs), + cubic(valCoord3D(seed, x0, y2, z0), valCoord3D(seed, x1, y2, z0), valCoord3D(seed, x2, y2, z0), valCoord3D(seed, x3, y2, z0), xs), + cubic(valCoord3D(seed, x0, y3, z0), valCoord3D(seed, x1, y3, z0), valCoord3D(seed, x2, y3, z0), valCoord3D(seed, x3, y3, z0), xs), + ys), + cubic( + cubic(valCoord3D(seed, x0, y0, z1), valCoord3D(seed, x1, y0, z1), valCoord3D(seed, x2, y0, z1), valCoord3D(seed, x3, y0, z1), xs), + cubic(valCoord3D(seed, x0, y1, z1), valCoord3D(seed, x1, y1, z1), valCoord3D(seed, x2, y1, z1), valCoord3D(seed, x3, y1, z1), xs), + cubic(valCoord3D(seed, x0, y2, z1), valCoord3D(seed, x1, y2, z1), valCoord3D(seed, x2, y2, z1), valCoord3D(seed, x3, y2, z1), xs), + cubic(valCoord3D(seed, x0, y3, z1), valCoord3D(seed, x1, y3, z1), valCoord3D(seed, x2, y3, z1), valCoord3D(seed, x3, y3, z1), xs), + ys), + cubic( + cubic(valCoord3D(seed, x0, y0, z2), valCoord3D(seed, x1, y0, z2), valCoord3D(seed, x2, y0, z2), valCoord3D(seed, x3, y0, z2), xs), + cubic(valCoord3D(seed, x0, y1, z2), valCoord3D(seed, x1, y1, z2), valCoord3D(seed, x2, y1, z2), valCoord3D(seed, x3, y1, z2), xs), + cubic(valCoord3D(seed, x0, y2, z2), valCoord3D(seed, x1, y2, z2), valCoord3D(seed, x2, y2, z2), valCoord3D(seed, x3, y2, z2), xs), + cubic(valCoord3D(seed, x0, y3, z2), valCoord3D(seed, x1, y3, z2), valCoord3D(seed, x2, y3, z2), valCoord3D(seed, x3, y3, z2), xs), + ys), + cubic( + cubic(valCoord3D(seed, x0, y0, z3), valCoord3D(seed, x1, y0, z3), valCoord3D(seed, x2, y0, z3), valCoord3D(seed, x3, y0, z3), xs), + cubic(valCoord3D(seed, x0, y1, z3), valCoord3D(seed, x1, y1, z3), valCoord3D(seed, x2, y1, z3), valCoord3D(seed, x3, y1, z3), xs), + cubic(valCoord3D(seed, x0, y2, z3), valCoord3D(seed, x1, y2, z3), valCoord3D(seed, x2, y2, z3), valCoord3D(seed, x3, y2, z3), xs), + cubic(valCoord3D(seed, x0, y3, z3), valCoord3D(seed, x1, y3, z3), valCoord3D(seed, x2, y3, z3), valCoord3D(seed, x3, y3, z3), xs), + ys), + zs) * CUBIC_3D_BOUNDING } \ No newline at end of file diff --git a/orx-noise/src/main/kotlin/Fractal.kt b/orx-noise/src/main/kotlin/Fractal.kt index 8bb926fb8..78ed02570 100644 --- a/orx-noise/src/main/kotlin/Fractal.kt +++ b/orx-noise/src/main/kotlin/Fractal.kt @@ -1,105 +1,105 @@ -package org.openrndr.extra.noise - -inline fun fbm(seed: Int, x: Double, y: Double, z: Double, crossinline noise: (Int, Double, Double, Double) -> Double, - octaves: Int = 8, lacunarity: Double = 0.5, gain: Double = 0.5): Double { - var sum = noise(seed, x, y, z) - var amp = 1.0 - - var x = x - var y = y - var z = z - for (i in 1 until octaves) { - x *= lacunarity - y *= lacunarity - z *= lacunarity - amp *= gain - sum += noise(seed + i, x, y, z) * amp - } - return sum -} - - -inline fun fbm(seed: Int, x: Double, y: Double, crossinline noise: (Int, Double, Double) -> Double, - octaves: Int = 8, lacunarity: Double = 0.5, gain: Double = 0.5): Double { - var sum = noise(seed, x, y) - var amp = 1.0 - - var x = x - var y = y - for (i in 1 until octaves) { - x *= lacunarity - y *= lacunarity - amp *= gain - sum += noise(seed + i, x, y) * amp - } - return sum -} - -inline fun billow(seed: Int, x: Double, y: Double, z: Double, crossinline noise: (Int, Double, Double, Double) -> Double, - octaves: Int = 8, lacunarity: Double = 0.5, gain: Double = 0.5) : Double { - var sum = Math.abs(noise(seed, x, y, z) * 2.0 - 1.0) - var amp = 1.0 - - var x = x - var y = y - var z = z - for (i in 1 until octaves) { - x *= lacunarity - y *= lacunarity - z *= lacunarity - amp *= gain - sum += Math.abs(noise(seed + i, x, y, z) * 2.0 - 1.0) * amp - } - return sum -} - -inline fun billow(seed: Int, x: Double, y: Double, crossinline noise: (Int, Double, Double) -> Double, - octaves: Int = 8, lacunarity: Double = 0.5, gain: Double = 0.5) : Double { - var sum = Math.abs(noise(seed, x, y) * 2.0 - 1.0) - var amp = 1.0 - - var x = x - var y = y - for (i in 1 until octaves) { - x *= lacunarity - y *= lacunarity - amp *= gain - sum += Math.abs(noise(seed + i, x, y) * 2.0 - 1.0) * amp - } - return sum -} - -inline fun rigid(seed: Int, x: Double, y: Double, crossinline noise: (Int, Double, Double) -> Double, - octaves: Int = 8, lacunarity: Double = 0.5, gain: Double = 0.5): Double { - var sum = 1.0 - Math.abs(noise(seed, x, y)) - var amp = 1.0 - - var x = x - var y = y - for (i in 1 until octaves) { - x *= lacunarity - y *= lacunarity - amp *= gain - sum -= (1.0 - Math.abs(noise(seed + i, x, y))) * amp - } - return sum -} - -inline fun rigid(seed: Int, x: Double, y: Double, z: Double, crossinline noise: (Int, Double, Double, Double) -> Double, - octaves: Int = 8, lacunarity: Double = 0.5, gain: Double = 0.5): Double { - var sum = 1.0 - Math.abs(noise(seed, x, y, z)) - var amp = 1.0 - - var x = x - var y = y - var z = z - for (i in 1 until octaves) { - x *= lacunarity - y *= lacunarity - z *= lacunarity - amp *= gain - sum -= (1.0 - Math.abs(noise(seed + i, x, y, z))) * amp - } - return sum -} - +package org.openrndr.extra.noise + +inline fun fbm(seed: Int, x: Double, y: Double, z: Double, crossinline noise: (Int, Double, Double, Double) -> Double, + octaves: Int = 8, lacunarity: Double = 0.5, gain: Double = 0.5): Double { + var sum = noise(seed, x, y, z) + var amp = 1.0 + + var x = x + var y = y + var z = z + for (i in 1 until octaves) { + x *= lacunarity + y *= lacunarity + z *= lacunarity + amp *= gain + sum += noise(seed + i, x, y, z) * amp + } + return sum +} + + +inline fun fbm(seed: Int, x: Double, y: Double, crossinline noise: (Int, Double, Double) -> Double, + octaves: Int = 8, lacunarity: Double = 0.5, gain: Double = 0.5): Double { + var sum = noise(seed, x, y) + var amp = 1.0 + + var x = x + var y = y + for (i in 1 until octaves) { + x *= lacunarity + y *= lacunarity + amp *= gain + sum += noise(seed + i, x, y) * amp + } + return sum +} + +inline fun billow(seed: Int, x: Double, y: Double, z: Double, crossinline noise: (Int, Double, Double, Double) -> Double, + octaves: Int = 8, lacunarity: Double = 0.5, gain: Double = 0.5) : Double { + var sum = Math.abs(noise(seed, x, y, z) * 2.0 - 1.0) + var amp = 1.0 + + var x = x + var y = y + var z = z + for (i in 1 until octaves) { + x *= lacunarity + y *= lacunarity + z *= lacunarity + amp *= gain + sum += Math.abs(noise(seed + i, x, y, z) * 2.0 - 1.0) * amp + } + return sum +} + +inline fun billow(seed: Int, x: Double, y: Double, crossinline noise: (Int, Double, Double) -> Double, + octaves: Int = 8, lacunarity: Double = 0.5, gain: Double = 0.5) : Double { + var sum = Math.abs(noise(seed, x, y) * 2.0 - 1.0) + var amp = 1.0 + + var x = x + var y = y + for (i in 1 until octaves) { + x *= lacunarity + y *= lacunarity + amp *= gain + sum += Math.abs(noise(seed + i, x, y) * 2.0 - 1.0) * amp + } + return sum +} + +inline fun rigid(seed: Int, x: Double, y: Double, crossinline noise: (Int, Double, Double) -> Double, + octaves: Int = 8, lacunarity: Double = 0.5, gain: Double = 0.5): Double { + var sum = 1.0 - Math.abs(noise(seed, x, y)) + var amp = 1.0 + + var x = x + var y = y + for (i in 1 until octaves) { + x *= lacunarity + y *= lacunarity + amp *= gain + sum -= (1.0 - Math.abs(noise(seed + i, x, y))) * amp + } + return sum +} + +inline fun rigid(seed: Int, x: Double, y: Double, z: Double, crossinline noise: (Int, Double, Double, Double) -> Double, + octaves: Int = 8, lacunarity: Double = 0.5, gain: Double = 0.5): Double { + var sum = 1.0 - Math.abs(noise(seed, x, y, z)) + var amp = 1.0 + + var x = x + var y = y + var z = z + for (i in 1 until octaves) { + x *= lacunarity + y *= lacunarity + z *= lacunarity + amp *= gain + sum -= (1.0 - Math.abs(noise(seed + i, x, y, z))) * amp + } + return sum +} + diff --git a/orx-noise/src/main/kotlin/GradCoord.kt b/orx-noise/src/main/kotlin/GradCoord.kt index 14ba46c97..91d84c868 100644 --- a/orx-noise/src/main/kotlin/GradCoord.kt +++ b/orx-noise/src/main/kotlin/GradCoord.kt @@ -1,156 +1,156 @@ -package org.openrndr.extra.noise - -import org.openrndr.math.Vector2 -import org.openrndr.math.Vector3 - - - -private const val X_PRIME = 1619 -private const val Y_PRIME = 31337 -private const val Z_PRIME = 6971 -private const val W_PRIME = 1013 - - -private val GRAD_2D = arrayOf(Vector2(-1.0, -1.0), Vector2(1.0, -1.0), Vector2(-1.0, 1.0), - Vector2(1.0, 1.0), Vector2(0.0, -1.0), Vector2(-1.0, 0.0), - Vector2(0.0, 1.0), Vector2(1.0, 0.0)) - - -private val GRAD_3D = arrayOf( - Vector3(1.0, 1.0, 0.0), Vector3(-1.0, 1.0, 0.0), Vector3(1.0, -1.0, 0.0), Vector3(-1.0, -1.0, 0.0), - Vector3(1.0, 0.0, 1.0), Vector3(-1.0, 0.0, 1.0), Vector3(1.0, 0.0, -1.0), Vector3(-1.0, 0.0, -1.0), - Vector3(0.0, 1.0, 1.0), Vector3(0.0, -1.0, 1.0), Vector3(0.0, 1.0, -1.0), Vector3(0.0, -1.0, -1.0), - Vector3(1.0, 1.0, 0.0), Vector3(0.0, -1.0, 1.0), Vector3(-1.0, 1.0, 0.0), Vector3(0.0, -1.0, -1.0)) - -fun gradCoord2D(seed: Int, x: Int, y: Int, xd: Double, yd: Double): Double { - var hash = seed - hash = hash xor X_PRIME * x - hash = hash xor Y_PRIME * y - - hash = hash * hash * hash * 60493 - hash = hash shr 13 xor hash - - val (x1, y1) = GRAD_2D[hash and 7] - - return xd * x1 + yd * y1 -} - -fun gradCoord3D(seed: Int, x: Int, y: Int, z: Int, xd: Double, yd: Double, zd: Double): Double { - var hash = seed - hash = hash xor X_PRIME * x - hash = hash xor Y_PRIME * y - hash = hash xor Z_PRIME * z - - hash *= hash * hash * 60493 - hash = hash shr 13 xor hash - - val g = GRAD_3D[hash and 15] - - return xd * g.x + yd * g.y + zd * g.z -} - - -fun gradCoord4D(seed: Int, x: Int, y: Int, z: Int, w: Int, xd: Double, yd: Double, zd: Double, wd: Double): Double { - var hash = seed - hash = hash xor X_PRIME * x - hash = hash xor Y_PRIME * y - hash = hash xor Z_PRIME * z - hash = hash xor W_PRIME * w - - hash = hash * hash * hash * 60493 - hash = hash shr 13 xor hash - - hash = hash and 31 - var a = yd - var b = zd - var c = wd // X,Y,Z - when (hash shr 3) { - // OR, DEPENDING ON HIGH ORDER 2 BITS: - 1 -> { - a = wd - b = xd - c = yd - } - 2 -> { - a = zd - b = wd - c = xd - } - 3 -> { - a = yd - b = zd - c = wd - } - }// W,X,Y - // Z,W,X - // Y,Z,W - return (if (hash and 4 == 0) -a else a) + (if (hash and 2 == 0) -b else b) + if (hash and 1 == 0) -c else c -} - - -fun hash2D(seed: Int, x: Int, y: Int): Int { - var hash = seed - hash = hash xor X_PRIME * x - hash = hash xor Y_PRIME * y - - hash = hash * hash * hash * 60493 - hash = hash shr 13 xor hash - - return hash -} - -fun hash3D(seed: Int, x: Int, y: Int, z: Int): Int { - var hash = seed - hash = hash xor X_PRIME * x - hash = hash xor Y_PRIME * y - hash = hash xor Z_PRIME * z - - hash = hash * hash * hash * 60493 - hash = hash shr 13 xor hash - - return hash -} - -fun hash4D(seed: Int, x: Int, y: Int, z: Int, w: Int): Int { - var hash = seed - hash = hash xor X_PRIME * x - hash = hash xor Y_PRIME * y - hash = hash xor Z_PRIME * z - hash = hash xor W_PRIME * w - - hash = hash * hash * hash * 60493 - hash = hash shr 13 xor hash - return hash -} - - -fun valCoord2D(seed: Int, x: Int, y: Int): Double { - var n = seed - n = n xor X_PRIME * x - n = n xor Y_PRIME * y - - return n * n * n * 60493 / 2147483648.0 -} - -fun valCoord3D(seed: Int, x: Int, y: Int, z: Int): Double { - var n = seed - n = n xor X_PRIME * x - n = n xor Y_PRIME * y - n = n xor Z_PRIME * z - - return n * n * n * 60493 / 2147483648.0 -} - - -private fun valCoord4D(seed: Int, x: Int, y: Int, z: Int, w: Int): Double { - var n = seed - n = n xor X_PRIME * x - n = n xor Y_PRIME * y - n = n xor Z_PRIME * z - n = n xor W_PRIME * w - - return n * n * n * 60493 / 2147483648.0 -} - -private val CELL_2D = arrayOf(Vector2(-0.4313539279, 0.1281943404), Vector2(-0.1733316799, 0.415278375), Vector2(-0.2821957395, -0.3505218461), Vector2(-0.2806473808, 0.3517627718), Vector2(0.3125508975, -0.3237467165), Vector2(0.3383018443, -0.2967353402), Vector2(-0.4393982022, -0.09710417025), Vector2(-0.4460443703, -0.05953502905), Vector2(-0.302223039, 0.3334085102), Vector2(-0.212681052, -0.3965687458), Vector2(-0.2991156529, 0.3361990872), Vector2(0.2293323691, 0.3871778202), Vector2(0.4475439151, -0.04695150755), Vector2(0.1777518, 0.41340573), Vector2(0.1688522499, -0.4171197882), Vector2(-0.0976597166, 0.4392750616), Vector2(0.08450188373, 0.4419948321), Vector2(-0.4098760448, -0.1857461384), Vector2(0.3476585782, -0.2857157906), Vector2(-0.3350670039, -0.30038326), Vector2(0.2298190031, -0.3868891648), Vector2(-0.01069924099, 0.449872789), Vector2(-0.4460141246, -0.05976119672), Vector2(0.3650293864, 0.2631606867), Vector2(-0.349479423, 0.2834856838), Vector2(-0.4122720642, 0.1803655873), Vector2(-0.267327811, 0.3619887311), Vector2(0.322124041, -0.3142230135), Vector2(0.2880445931, -0.3457315612), Vector2(0.3892170926, -0.2258540565), Vector2(0.4492085018, -0.02667811596), Vector2(-0.4497724772, 0.01430799601), Vector2(0.1278175387, -0.4314657307), Vector2(-0.03572100503, 0.4485799926), Vector2(-0.4297407068, -0.1335025276), Vector2(-0.3217817723, 0.3145735065), Vector2(-0.3057158873, 0.3302087162), Vector2(-0.414503978, 0.1751754899), Vector2(-0.3738139881, 0.2505256519), Vector2(0.2236891408, -0.3904653228), Vector2(0.002967775577, -0.4499902136), Vector2(0.1747128327, -0.4146991995), Vector2(-0.4423772489, -0.08247647938), Vector2(-0.2763960987, -0.355112935), Vector2(-0.4019385906, -0.2023496216), Vector2(0.3871414161, -0.2293938184), Vector2(-0.430008727, 0.1326367019), Vector2(-0.03037574274, -0.4489736231), Vector2(-0.3486181573, 0.2845441624), Vector2(0.04553517144, -0.4476902368), Vector2(-0.0375802926, 0.4484280562), Vector2(0.3266408905, 0.3095250049), Vector2(0.06540017593, -0.4452222108), Vector2(0.03409025829, 0.448706869), Vector2(-0.4449193635, 0.06742966669), Vector2(-0.4255936157, -0.1461850686), Vector2(0.449917292, 0.008627302568), Vector2(0.05242606404, 0.4469356864), Vector2(-0.4495305179, -0.02055026661), Vector2(-0.1204775703, 0.4335725488), Vector2(-0.341986385, -0.2924813028), Vector2(0.3865320182, 0.2304191809), Vector2(0.04506097811, -0.447738214), Vector2(-0.06283465979, 0.4455915232), Vector2(0.3932600341, -0.2187385324), Vector2(0.4472261803, -0.04988730975), Vector2(0.3753571011, -0.2482076684), Vector2(-0.273662295, 0.357223947), Vector2(0.1700461538, 0.4166344988), Vector2(0.4102692229, 0.1848760794), Vector2(0.323227187, -0.3130881435), Vector2(-0.2882310238, -0.3455761521), Vector2(0.2050972664, 0.4005435199), Vector2(0.4414085979, -0.08751256895), Vector2(-0.1684700334, 0.4172743077), Vector2(-0.003978032396, 0.4499824166), Vector2(-0.2055133639, 0.4003301853), Vector2(-0.006095674897, -0.4499587123), Vector2(-0.1196228124, -0.4338091548), Vector2(0.3901528491, -0.2242337048), Vector2(0.01723531752, 0.4496698165), Vector2(-0.3015070339, 0.3340561458), Vector2(-0.01514262423, -0.4497451511), Vector2(-0.4142574071, -0.1757577897), Vector2(-0.1916377265, -0.4071547394), Vector2(0.3749248747, 0.2488600778), Vector2(-0.2237774255, 0.3904147331), Vector2(-0.4166343106, -0.1700466149), Vector2(0.3619171625, 0.267424695), Vector2(0.1891126846, -0.4083336779), Vector2(-0.3127425077, 0.323561623), Vector2(-0.3281807787, 0.307891826), Vector2(-0.2294806661, 0.3870899429), Vector2(-0.3445266136, 0.2894847362), Vector2(-0.4167095422, -0.1698621719), Vector2(-0.257890321, -0.3687717212), Vector2(-0.3612037825, 0.2683874578), Vector2(0.2267996491, 0.3886668486), Vector2(0.207157062, 0.3994821043), Vector2(0.08355176718, -0.4421754202), Vector2(-0.4312233307, 0.1286329626), Vector2(0.3257055497, 0.3105090899), Vector2(0.177701095, -0.4134275279), Vector2(-0.445182522, 0.06566979625), Vector2(0.3955143435, 0.2146355146), Vector2(-0.4264613988, 0.1436338239), Vector2(-0.3793799665, -0.2420141339), Vector2(0.04617599081, -0.4476245948), Vector2(-0.371405428, -0.2540826796), Vector2(0.2563570295, -0.3698392535), Vector2(0.03476646309, 0.4486549822), Vector2(-0.3065454405, 0.3294387544), Vector2(-0.2256979823, 0.3893076172), Vector2(0.4116448463, -0.1817925206), Vector2(-0.2907745828, -0.3434387019), Vector2(0.2842278468, -0.348876097), Vector2(0.3114589359, -0.3247973695), Vector2(0.4464155859, -0.0566844308), Vector2(-0.3037334033, -0.3320331606), Vector2(0.4079607166, 0.1899159123), Vector2(-0.3486948919, -0.2844501228), Vector2(0.3264821436, 0.3096924441), Vector2(0.3211142406, 0.3152548881), Vector2(0.01183382662, 0.4498443737), Vector2(0.4333844092, 0.1211526057), Vector2(0.3118668416, 0.324405723), Vector2(-0.272753471, 0.3579183483), Vector2(-0.422228622, -0.1556373694), Vector2(-0.1009700099, -0.4385260051), Vector2(-0.2741171231, -0.3568750521), Vector2(-0.1465125133, 0.4254810025), Vector2(0.2302279044, -0.3866459777), Vector2(-0.3699435608, 0.2562064828), Vector2(0.105700352, -0.4374099171), Vector2(-0.2646713633, 0.3639355292), Vector2(0.3521828122, 0.2801200935), Vector2(-0.1864187807, -0.4095705534), Vector2(0.1994492955, -0.4033856449), Vector2(0.3937065066, 0.2179339044), Vector2(-0.3226158377, 0.3137180602), Vector2(0.3796235338, 0.2416318948), Vector2(0.1482921929, 0.4248640083), Vector2(-0.407400394, 0.1911149365), Vector2(0.4212853031, 0.1581729856), Vector2(-0.2621297173, 0.3657704353), Vector2(-0.2536986953, -0.3716678248), Vector2(-0.2100236383, 0.3979825013), Vector2(0.3624152444, 0.2667493029), Vector2(-0.3645038479, -0.2638881295), Vector2(0.2318486784, 0.3856762766), Vector2(-0.3260457004, 0.3101519002), Vector2(-0.2130045332, -0.3963950918), Vector2(0.3814998766, -0.2386584257), Vector2(-0.342977305, 0.2913186713), Vector2(-0.4355865605, 0.1129794154), Vector2(-0.2104679605, 0.3977477059), Vector2(0.3348364681, -0.3006402163), Vector2(0.3430468811, 0.2912367377), Vector2(-0.2291836801, -0.3872658529), Vector2(0.2547707298, -0.3709337882), Vector2(0.4236174945, -0.151816397), Vector2(-0.15387742, 0.4228731957), Vector2(-0.4407449312, 0.09079595574), Vector2(-0.06805276192, -0.444824484), Vector2(0.4453517192, -0.06451237284), Vector2(0.2562464609, -0.3699158705), Vector2(0.3278198355, -0.3082761026), Vector2(-0.4122774207, -0.1803533432), Vector2(0.3354090914, -0.3000012356), Vector2(0.446632869, -0.05494615882), Vector2(-0.1608953296, 0.4202531296), Vector2(-0.09463954939, 0.4399356268), Vector2(-0.02637688324, -0.4492262904), Vector2(0.447102804, -0.05098119915), Vector2(-0.4365670908, 0.1091291678), Vector2(-0.3959858651, 0.2137643437), Vector2(-0.4240048207, -0.1507312575), Vector2(-0.3882794568, 0.2274622243), Vector2(-0.4283652566, -0.1378521198), Vector2(0.3303888091, 0.305521251), Vector2(0.3321434919, -0.3036127481), Vector2(-0.413021046, -0.1786438231), Vector2(0.08403060337, -0.4420846725), Vector2(-0.3822882919, 0.2373934748), Vector2(-0.3712395594, -0.2543249683), Vector2(0.4472363971, -0.04979563372), Vector2(-0.4466591209, 0.05473234629), Vector2(0.0486272539, -0.4473649407), Vector2(-0.4203101295, -0.1607463688), Vector2(0.2205360833, 0.39225481), Vector2(-0.3624900666, 0.2666476169), Vector2(-0.4036086833, -0.1989975647), Vector2(0.2152727807, 0.3951678503), Vector2(-0.4359392962, -0.1116106179), Vector2(0.4178354266, 0.1670735057), Vector2(0.2007630161, 0.4027334247), Vector2(-0.07278067175, -0.4440754146), Vector2(0.3644748615, -0.2639281632), Vector2(-0.4317451775, 0.126870413), Vector2(-0.297436456, 0.3376855855), Vector2(-0.2998672222, 0.3355289094), Vector2(-0.2673674124, 0.3619594822), Vector2(0.2808423357, 0.3516071423), Vector2(0.3498946567, 0.2829730186), Vector2(-0.2229685561, 0.390877248), Vector2(0.3305823267, 0.3053118493), Vector2(-0.2436681211, -0.3783197679), Vector2(-0.03402776529, 0.4487116125), Vector2(-0.319358823, 0.3170330301), Vector2(0.4454633477, -0.06373700535), Vector2(0.4483504221, 0.03849544189), Vector2(-0.4427358436, -0.08052932871), Vector2(0.05452298565, 0.4466847255), Vector2(-0.2812560807, 0.3512762688), Vector2(0.1266696921, 0.4318041097), Vector2(-0.3735981243, 0.2508474468), Vector2(0.2959708351, -0.3389708908), Vector2(-0.3714377181, 0.254035473), Vector2(-0.404467102, -0.1972469604), Vector2(0.1636165687, -0.419201167), Vector2(0.3289185495, -0.3071035458), Vector2(-0.2494824991, -0.3745109914), Vector2(0.03283133272, 0.4488007393), Vector2(-0.166306057, -0.4181414777), Vector2(-0.106833179, 0.4371346153), Vector2(0.06440260376, -0.4453676062), Vector2(-0.4483230967, 0.03881238203), Vector2(-0.421377757, -0.1579265206), Vector2(0.05097920662, -0.4471030312), Vector2(0.2050584153, -0.4005634111), Vector2(0.4178098529, -0.167137449), Vector2(-0.3565189504, -0.2745801121), Vector2(0.4478398129, 0.04403977727), Vector2(-0.3399999602, -0.2947881053), Vector2(0.3767121994, 0.2461461331), Vector2(-0.3138934434, 0.3224451987), Vector2(-0.1462001792, -0.4255884251), Vector2(0.3970290489, -0.2118205239), Vector2(0.4459149305, -0.06049689889), Vector2(-0.4104889426, -0.1843877112), Vector2(0.1475103971, -0.4251360756), Vector2(0.09258030352, 0.4403735771), Vector2(-0.1589664637, -0.4209865359), Vector2(0.2482445008, 0.3753327428), Vector2(0.4383624232, -0.1016778537), Vector2(0.06242802956, 0.4456486745), Vector2(0.2846591015, -0.3485243118), Vector2(-0.344202744, -0.2898697484), Vector2(0.1198188883, -0.4337550392), Vector2(-0.243590703, 0.3783696201), Vector2(0.2958191174, -0.3391033025), Vector2(-0.1164007991, 0.4346847754), Vector2(0.1274037151, -0.4315881062), Vector2(0.368047306, 0.2589231171), Vector2(0.2451436949, 0.3773652989), Vector2(-0.4314509715, 0.12786735)) -private val CELL_3D = arrayOf(Vector3(0.1453787434, -0.4149781685, -0.0956981749), Vector3(-0.01242829687, -0.1457918398, -0.4255470325), Vector3(0.2877979582, -0.02606483451, -0.3449535616), Vector3(-0.07732986802, 0.2377094325, 0.3741848704), Vector3(0.1107205875, -0.3552302079, -0.2530858567), Vector3(0.2755209141, 0.2640521179, -0.238463215), Vector3(0.294168941, 0.1526064594, 0.3044271714), Vector3(0.4000921098, -0.2034056362, 0.03244149937), Vector3(-0.1697304074, 0.3970864695, -0.1265461359), Vector3(-0.1483224484, -0.3859694688, 0.1775613147), Vector3(0.2623596946, -0.2354852944, 0.2796677792), Vector3(-0.2709003183, 0.3505271138, -0.07901746678), Vector3(-0.03516550699, 0.3885234328, 0.2243054374), Vector3(-0.1267712655, 0.1920044036, 0.3867342179), Vector3(0.02952021915, 0.4409685861, 0.08470692262), Vector3(-0.2806854217, -0.266996757, 0.2289725438), Vector3(-0.171159547, 0.2141185563, 0.3568720405), Vector3(0.2113227183, 0.3902405947, -0.07453178509), Vector3(-0.1024352839, 0.2128044156, -0.3830421561), Vector3(-0.3304249877, -0.1566986703, 0.2622305365), Vector3(0.2091111325, 0.3133278055, -0.2461670583), Vector3(0.344678154, -0.1944240454, -0.2142341261), Vector3(0.1984478035, -0.3214342325, -0.2445373252), Vector3(-0.2929008603, 0.2262915116, 0.2559320961), Vector3(-0.1617332831, 0.006314769776, -0.4198838754), Vector3(-0.3582060271, -0.148303178, -0.2284613961), Vector3(-0.1852067326, -0.3454119342, -0.2211087107), Vector3(0.3046301062, 0.1026310383, 0.314908508), Vector3(-0.03816768434, -0.2551766358, -0.3686842991), Vector3(-0.4084952196, 0.1805950793, 0.05492788837), Vector3(-0.02687443361, -0.2749741471, 0.3551999201), Vector3(-0.03801098351, 0.3277859044, 0.3059600725), Vector3(0.2371120802, 0.2900386767, -0.2493099024), Vector3(0.4447660503, 0.03946930643, 0.05590469027), Vector3(0.01985147278, -0.01503183293, -0.4493105419), Vector3(0.4274339143, 0.03345994256, -0.1366772882), Vector3(-0.2072988631, 0.2871414597, -0.2776273824), Vector3(-0.3791240978, 0.1281177671, 0.2057929936), Vector3(-0.2098721267, -0.1007087278, -0.3851122467), Vector3(0.01582798878, 0.4263894424, 0.1429738373), Vector3(-0.1888129464, -0.3160996813, -0.2587096108), Vector3(0.1612988974, -0.1974805082, -0.3707885038), Vector3(-0.08974491322, 0.229148752, -0.3767448739), Vector3(0.07041229526, 0.4150230285, -0.1590534329), Vector3(-0.1082925611, -0.1586061639, 0.4069604477), Vector3(0.2474100658, -0.3309414609, 0.1782302128), Vector3(-0.1068836661, -0.2701644537, -0.3436379634), Vector3(0.2396452163, 0.06803600538, -0.3747549496), Vector3(-0.3063886072, 0.2597428179, 0.2028785103), Vector3(0.1593342891, -0.3114350249, -0.2830561951), Vector3(0.2709690528, 0.1412648683, -0.3303331794), Vector3(-0.1519780427, 0.3623355133, 0.2193527988), Vector3(0.1699773681, 0.3456012883, 0.2327390037), Vector3(-0.1986155616, 0.3836276443, -0.1260225743), Vector3(-0.1887482106, -0.2050154888, -0.353330953), Vector3(0.2659103394, 0.3015631259, -0.2021172246), Vector3(-0.08838976154, -0.4288819642, -0.1036702021), Vector3(-0.04201869311, 0.3099592485, 0.3235115047), Vector3(-0.3230334656, 0.201549922, -0.2398478873), Vector3(0.2612720941, 0.2759854499, -0.2409749453), Vector3(0.385713046, 0.2193460345, 0.07491837764), Vector3(0.07654967953, 0.3721732183, 0.241095919), Vector3(0.4317038818, -0.02577753072, 0.1243675091), Vector3(-0.2890436293, -0.3418179959, -0.04598084447), Vector3(-0.2201947582, 0.383023377, -0.08548310451), Vector3(0.4161322773, -0.1669634289, -0.03817251927), Vector3(0.2204718095, 0.02654238946, -0.391391981), Vector3(-0.1040307469, 0.3890079625, -0.2008741118), Vector3(-0.1432122615, 0.371614387, -0.2095065525), Vector3(0.3978380468, -0.06206669342, 0.2009293758), Vector3(-0.2599274663, 0.2616724959, -0.2578084893), Vector3(0.4032618332, -0.1124593585, 0.1650235939), Vector3(-0.08953470255, -0.3048244735, 0.3186935478), Vector3(0.118937202, -0.2875221847, 0.325092195), Vector3(0.02167047076, -0.03284630549, -0.4482761547), Vector3(-0.3411343612, 0.2500031105, 0.1537068389), Vector3(0.3162964612, 0.3082064153, -0.08640228117), Vector3(0.2355138889, -0.3439334267, -0.1695376245), Vector3(-0.02874541518, -0.3955933019, 0.2125550295), Vector3(-0.2461455173, 0.02020282325, -0.3761704803), Vector3(0.04208029445, -0.4470439576, 0.02968078139), Vector3(0.2727458746, 0.2288471896, -0.2752065618), Vector3(-0.1347522818, -0.02720848277, -0.4284874806), Vector3(0.3829624424, 0.1231931484, -0.2016512234), Vector3(-0.3547613644, 0.1271702173, 0.2459107769), Vector3(0.2305790207, 0.3063895591, 0.2354968222), Vector3(-0.08323845599, -0.1922245118, 0.3982726409), Vector3(0.2993663085, -0.2619918095, -0.2103333191), Vector3(-0.2154865723, 0.2706747713, 0.287751117), Vector3(0.01683355354, -0.2680655787, -0.3610505186), Vector3(0.05240429123, 0.4335128183, -0.1087217856), Vector3(0.00940104872, -0.4472890582, 0.04841609928), Vector3(0.3465688735, 0.01141914583, -0.2868093776), Vector3(-0.3706867948, -0.2551104378, 0.003156692623), Vector3(0.2741169781, 0.2139972417, -0.2855959784), Vector3(0.06413433865, 0.1708718512, 0.4113266307), Vector3(-0.388187972, -0.03973280434, -0.2241236325), Vector3(0.06419469312, -0.2803682491, 0.3460819069), Vector3(-0.1986120739, -0.3391173584, 0.2192091725), Vector3(-0.203203009, -0.3871641506, 0.1063600375), Vector3(-0.1389736354, -0.2775901578, -0.3257760473), Vector3(-0.06555641638, 0.342253257, -0.2847192729), Vector3(-0.2529246486, -0.2904227915, 0.2327739768), Vector3(0.1444476522, 0.1069184044, 0.4125570634), Vector3(-0.3643780054, -0.2447099973, -0.09922543227), Vector3(0.4286142488, -0.1358496089, -0.01829506817), Vector3(0.165872923, -0.3136808464, -0.2767498872), Vector3(0.2219610524, -0.3658139958, 0.1393320198), Vector3(0.04322940318, -0.3832730794, 0.2318037215), Vector3(-0.08481269795, -0.4404869674, -0.03574965489), Vector3(0.1822082075, -0.3953259299, 0.1140946023), Vector3(-0.3269323334, 0.3036542563, 0.05838957105), Vector3(-0.4080485344, 0.04227858267, -0.184956522), Vector3(0.2676025294, -0.01299671652, 0.36155217), Vector3(0.3024892441, -0.1009990293, -0.3174892964), Vector3(0.1448494052, 0.425921681, -0.0104580805), Vector3(0.4198402157, 0.08062320474, 0.1404780841), Vector3(-0.3008872161, -0.333040905, -0.03241355801), Vector3(0.3639310428, -0.1291284382, -0.2310412139), Vector3(0.3295806598, 0.0184175994, -0.3058388149), Vector3(0.2776259487, -0.2974929052, -0.1921504723), Vector3(0.4149000507, -0.144793182, -0.09691688386), Vector3(0.145016715, -0.0398992945, 0.4241205002), Vector3(0.09299023471, -0.299732164, -0.3225111565), Vector3(0.1028907093, -0.361266869, 0.247789732), Vector3(0.2683057049, -0.07076041213, -0.3542668666), Vector3(-0.4227307273, -0.07933161816, -0.1323073187), Vector3(-0.1781224702, 0.1806857196, -0.3716517945), Vector3(0.4390788626, -0.02841848598, -0.09435116353), Vector3(0.2972583585, 0.2382799621, -0.2394997452), Vector3(-0.1707002821, 0.2215845691, 0.3525077196), Vector3(0.3806686614, 0.1471852559, -0.1895464869), Vector3(-0.1751445661, -0.274887877, 0.3102596268), Vector3(-0.2227237566, -0.2316778837, 0.3149912482), Vector3(0.1369633021, 0.1341343041, -0.4071228836), Vector3(-0.3529503428, -0.2472893463, -0.129514612), Vector3(-0.2590744185, -0.2985577559, -0.2150435121), Vector3(-0.3784019401, 0.2199816631, -0.1044989934), Vector3(-0.05635805671, 0.1485737441, 0.4210102279), Vector3(0.3251428613, 0.09666046873, -0.2957006485), Vector3(-0.4190995804, 0.1406751354, -0.08405978803), Vector3(-0.3253150961, -0.3080335042, -0.04225456877), Vector3(0.2857945863, -0.05796152095, 0.3427271751), Vector3(-0.2733604046, 0.1973770973, -0.2980207554), Vector3(0.219003657, 0.2410037886, -0.3105713639), Vector3(0.3182767252, -0.271342949, 0.1660509868), Vector3(-0.03222023115, -0.3331161506, -0.300824678), Vector3(-0.3087780231, 0.1992794134, -0.2596995338), Vector3(-0.06487611647, -0.4311322747, 0.1114273361), Vector3(0.3921171432, -0.06294284106, -0.2116183942), Vector3(-0.1606404506, -0.358928121, -0.2187812825), Vector3(-0.03767771199, -0.2290351443, 0.3855169162), Vector3(0.1394866832, -0.3602213994, 0.2308332918), Vector3(-0.4345093872, 0.005751117145, 0.1169124335), Vector3(-0.1044637494, 0.4168128432, -0.1336202785), Vector3(0.2658727501, 0.2551943237, 0.2582393035), Vector3(0.2051461999, 0.1975390727, 0.3484154868), Vector3(-0.266085566, 0.23483312, 0.2766800993), Vector3(0.07849405464, -0.3300346342, -0.2956616708), Vector3(-0.2160686338, 0.05376451292, -0.3910546287), Vector3(-0.185779186, 0.2148499206, 0.3490352499), Vector3(0.02492421743, -0.3229954284, -0.3123343347), Vector3(-0.120167831, 0.4017266681, 0.1633259825), Vector3(-0.02160084693, -0.06885389554, 0.4441762538), Vector3(0.2597670064, 0.3096300784, 0.1978643903), Vector3(-0.1611553854, -0.09823036005, 0.4085091653), Vector3(-0.3278896792, 0.1461670309, 0.2713366126), Vector3(0.2822734956, 0.03754421121, -0.3484423997), Vector3(0.03169341113, 0.347405252, -0.2842624114), Vector3(0.2202613604, -0.3460788041, -0.1849713341), Vector3(0.2933396046, 0.3031973659, 0.1565989581), Vector3(-0.3194922995, 0.2453752201, -0.200538455), Vector3(-0.3441586045, -0.1698856132, -0.2349334659), Vector3(0.2703645948, -0.3574277231, 0.04060059933), Vector3(0.2298568861, 0.3744156221, 0.0973588921), Vector3(0.09326603877, -0.3170108894, 0.3054595587), Vector3(-0.1116165319, -0.2985018719, 0.3177080142), Vector3(0.2172907365, -0.3460005203, -0.1885958001), Vector3(0.1991339479, 0.3820341668, -0.1299829458), Vector3(-0.0541918155, -0.2103145071, 0.39412061), Vector3(0.08871336998, 0.2012117383, 0.3926114802), Vector3(0.2787673278, 0.3505404674, 0.04370535101), Vector3(-0.322166438, 0.3067213525, 0.06804996813), Vector3(-0.4277366384, 0.132066775, 0.04582286686), Vector3(0.240131882, -0.1612516055, 0.344723946), Vector3(0.1448607981, -0.2387819045, 0.3528435224), Vector3(-0.3837065682, -0.2206398454, 0.08116235683), Vector3(-0.4382627882, -0.09082753406, -0.04664855374), Vector3(-0.37728353, 0.05445141085, 0.2391488697), Vector3(0.1259579313, 0.348394558, 0.2554522098), Vector3(-0.1406285511, -0.270877371, -0.3306796947), Vector3(-0.1580694418, 0.4162931958, -0.06491553533), Vector3(0.2477612106, -0.2927867412, -0.2353514536), Vector3(0.2916132853, 0.3312535401, 0.08793624968), Vector3(0.07365265219, -0.1666159848, 0.411478311), Vector3(-0.26126526, -0.2422237692, 0.2748965434), Vector3(-0.3721862032, 0.252790166, 0.008634938242), Vector3(-0.3691191571, -0.255281188, 0.03290232422), Vector3(0.2278441737, -0.3358364886, 0.1944244981), Vector3(0.363398169, -0.2310190248, 0.1306597909), Vector3(-0.304231482, -0.2698452035, 0.1926830856), Vector3(-0.3199312232, 0.316332536, -0.008816977938), Vector3(0.2874852279, 0.1642275508, -0.304764754), Vector3(-0.1451096801, 0.3277541114, -0.2720669462), Vector3(0.3220090754, 0.0511344108, 0.3101538769), Vector3(-0.1247400865, -0.04333605335, -0.4301882115), Vector3(-0.2829555867, -0.3056190617, -0.1703910946), Vector3(0.1069384374, 0.3491024667, -0.2630430352), Vector3(-0.1420661144, -0.3055376754, -0.2982682484), Vector3(-0.250548338, 0.3156466809, -0.2002316239), Vector3(0.3265787872, 0.1871229129, 0.2466400438), Vector3(0.07646097258, -0.3026690852, 0.324106687), Vector3(0.3451771584, 0.2757120714, -0.0856480183), Vector3(0.298137964, 0.2852657134, 0.179547284), Vector3(0.2812250376, 0.3466716415, 0.05684409612), Vector3(0.4390345476, -0.09790429955, -0.01278335452), Vector3(0.2148373234, 0.1850172527, 0.3494474791), Vector3(0.2595421179, -0.07946825393, 0.3589187731), Vector3(0.3182823114, -0.307355516, -0.08203022006), Vector3(-0.4089859285, -0.04647718411, 0.1818526372), Vector3(-0.2826749061, 0.07417482322, 0.3421885344), Vector3(0.3483864637, 0.225442246, -0.1740766085), Vector3(-0.3226415069, -0.1420585388, -0.2796816575), Vector3(0.4330734858, -0.118868561, -0.02859407492), Vector3(-0.08717822568, -0.3909896417, -0.2050050172), Vector3(-0.2149678299, 0.3939973956, -0.03247898316), Vector3(-0.2687330705, 0.322686276, -0.1617284888), Vector3(0.2105665099, -0.1961317136, -0.3459683451), Vector3(0.4361845915, -0.1105517485, 0.004616608544), Vector3(0.05333333359, -0.313639498, -0.3182543336), Vector3(-0.05986216652, 0.1361029153, -0.4247264031), Vector3(0.3664988455, 0.2550543014, -0.05590974511), Vector3(-0.2341015558, -0.182405731, 0.3382670703), Vector3(-0.04730947785, -0.4222150243, -0.1483114513), Vector3(-0.2391566239, -0.2577696514, -0.2808182972), Vector3(-0.1242081035, 0.4256953395, -0.07652336246), Vector3(0.2614832715, -0.3650179274, 0.02980623099), Vector3(-0.2728794681, -0.3499628774, 0.07458404908), Vector3(0.007892900508, -0.1672771315, 0.4176793787), Vector3(-0.01730330376, 0.2978486637, -0.3368779738), Vector3(0.2054835762, -0.3252600376, -0.2334146693), Vector3(-0.3231994983, 0.1564282844, -0.2712420987), Vector3(-0.2669545963, 0.2599343665, -0.2523278991), Vector3(-0.05554372779, 0.3170813944, -0.3144428146), Vector3(-0.2083935713, -0.310922837, -0.2497981362), Vector3(0.06989323478, -0.3156141536, 0.3130537363), Vector3(0.3847566193, -0.1605309138, -0.1693876312), Vector3(-0.3026215288, -0.3001537679, -0.1443188342), Vector3(0.3450735512, 0.08611519592, 0.2756962409), Vector3(0.1814473292, -0.2788782453, -0.3029914042), Vector3(-0.03855010448, 0.09795110726, 0.4375151083), Vector3(0.3533670318, 0.2665752752, 0.08105160988), Vector3(-0.007945601311, 0.140359426, -0.4274764309), Vector3(0.4063099273, -0.1491768253, -0.1231199324), Vector3(-0.2016773589, 0.008816271194, -0.4021797064), Vector3(-0.07527055435, -0.425643481, -0.1251477955)) +package org.openrndr.extra.noise + +import org.openrndr.math.Vector2 +import org.openrndr.math.Vector3 + + + +private const val X_PRIME = 1619 +private const val Y_PRIME = 31337 +private const val Z_PRIME = 6971 +private const val W_PRIME = 1013 + + +private val GRAD_2D = arrayOf(Vector2(-1.0, -1.0), Vector2(1.0, -1.0), Vector2(-1.0, 1.0), + Vector2(1.0, 1.0), Vector2(0.0, -1.0), Vector2(-1.0, 0.0), + Vector2(0.0, 1.0), Vector2(1.0, 0.0)) + + +private val GRAD_3D = arrayOf( + Vector3(1.0, 1.0, 0.0), Vector3(-1.0, 1.0, 0.0), Vector3(1.0, -1.0, 0.0), Vector3(-1.0, -1.0, 0.0), + Vector3(1.0, 0.0, 1.0), Vector3(-1.0, 0.0, 1.0), Vector3(1.0, 0.0, -1.0), Vector3(-1.0, 0.0, -1.0), + Vector3(0.0, 1.0, 1.0), Vector3(0.0, -1.0, 1.0), Vector3(0.0, 1.0, -1.0), Vector3(0.0, -1.0, -1.0), + Vector3(1.0, 1.0, 0.0), Vector3(0.0, -1.0, 1.0), Vector3(-1.0, 1.0, 0.0), Vector3(0.0, -1.0, -1.0)) + +fun gradCoord2D(seed: Int, x: Int, y: Int, xd: Double, yd: Double): Double { + var hash = seed + hash = hash xor X_PRIME * x + hash = hash xor Y_PRIME * y + + hash = hash * hash * hash * 60493 + hash = hash shr 13 xor hash + + val (x1, y1) = GRAD_2D[hash and 7] + + return xd * x1 + yd * y1 +} + +fun gradCoord3D(seed: Int, x: Int, y: Int, z: Int, xd: Double, yd: Double, zd: Double): Double { + var hash = seed + hash = hash xor X_PRIME * x + hash = hash xor Y_PRIME * y + hash = hash xor Z_PRIME * z + + hash *= hash * hash * 60493 + hash = hash shr 13 xor hash + + val g = GRAD_3D[hash and 15] + + return xd * g.x + yd * g.y + zd * g.z +} + + +fun gradCoord4D(seed: Int, x: Int, y: Int, z: Int, w: Int, xd: Double, yd: Double, zd: Double, wd: Double): Double { + var hash = seed + hash = hash xor X_PRIME * x + hash = hash xor Y_PRIME * y + hash = hash xor Z_PRIME * z + hash = hash xor W_PRIME * w + + hash = hash * hash * hash * 60493 + hash = hash shr 13 xor hash + + hash = hash and 31 + var a = yd + var b = zd + var c = wd // X,Y,Z + when (hash shr 3) { + // OR, DEPENDING ON HIGH ORDER 2 BITS: + 1 -> { + a = wd + b = xd + c = yd + } + 2 -> { + a = zd + b = wd + c = xd + } + 3 -> { + a = yd + b = zd + c = wd + } + }// W,X,Y + // Z,W,X + // Y,Z,W + return (if (hash and 4 == 0) -a else a) + (if (hash and 2 == 0) -b else b) + if (hash and 1 == 0) -c else c +} + + +fun hash2D(seed: Int, x: Int, y: Int): Int { + var hash = seed + hash = hash xor X_PRIME * x + hash = hash xor Y_PRIME * y + + hash = hash * hash * hash * 60493 + hash = hash shr 13 xor hash + + return hash +} + +fun hash3D(seed: Int, x: Int, y: Int, z: Int): Int { + var hash = seed + hash = hash xor X_PRIME * x + hash = hash xor Y_PRIME * y + hash = hash xor Z_PRIME * z + + hash = hash * hash * hash * 60493 + hash = hash shr 13 xor hash + + return hash +} + +fun hash4D(seed: Int, x: Int, y: Int, z: Int, w: Int): Int { + var hash = seed + hash = hash xor X_PRIME * x + hash = hash xor Y_PRIME * y + hash = hash xor Z_PRIME * z + hash = hash xor W_PRIME * w + + hash = hash * hash * hash * 60493 + hash = hash shr 13 xor hash + return hash +} + + +fun valCoord2D(seed: Int, x: Int, y: Int): Double { + var n = seed + n = n xor X_PRIME * x + n = n xor Y_PRIME * y + + return n * n * n * 60493 / 2147483648.0 +} + +fun valCoord3D(seed: Int, x: Int, y: Int, z: Int): Double { + var n = seed + n = n xor X_PRIME * x + n = n xor Y_PRIME * y + n = n xor Z_PRIME * z + + return n * n * n * 60493 / 2147483648.0 +} + + +private fun valCoord4D(seed: Int, x: Int, y: Int, z: Int, w: Int): Double { + var n = seed + n = n xor X_PRIME * x + n = n xor Y_PRIME * y + n = n xor Z_PRIME * z + n = n xor W_PRIME * w + + return n * n * n * 60493 / 2147483648.0 +} + +private val CELL_2D = arrayOf(Vector2(-0.4313539279, 0.1281943404), Vector2(-0.1733316799, 0.415278375), Vector2(-0.2821957395, -0.3505218461), Vector2(-0.2806473808, 0.3517627718), Vector2(0.3125508975, -0.3237467165), Vector2(0.3383018443, -0.2967353402), Vector2(-0.4393982022, -0.09710417025), Vector2(-0.4460443703, -0.05953502905), Vector2(-0.302223039, 0.3334085102), Vector2(-0.212681052, -0.3965687458), Vector2(-0.2991156529, 0.3361990872), Vector2(0.2293323691, 0.3871778202), Vector2(0.4475439151, -0.04695150755), Vector2(0.1777518, 0.41340573), Vector2(0.1688522499, -0.4171197882), Vector2(-0.0976597166, 0.4392750616), Vector2(0.08450188373, 0.4419948321), Vector2(-0.4098760448, -0.1857461384), Vector2(0.3476585782, -0.2857157906), Vector2(-0.3350670039, -0.30038326), Vector2(0.2298190031, -0.3868891648), Vector2(-0.01069924099, 0.449872789), Vector2(-0.4460141246, -0.05976119672), Vector2(0.3650293864, 0.2631606867), Vector2(-0.349479423, 0.2834856838), Vector2(-0.4122720642, 0.1803655873), Vector2(-0.267327811, 0.3619887311), Vector2(0.322124041, -0.3142230135), Vector2(0.2880445931, -0.3457315612), Vector2(0.3892170926, -0.2258540565), Vector2(0.4492085018, -0.02667811596), Vector2(-0.4497724772, 0.01430799601), Vector2(0.1278175387, -0.4314657307), Vector2(-0.03572100503, 0.4485799926), Vector2(-0.4297407068, -0.1335025276), Vector2(-0.3217817723, 0.3145735065), Vector2(-0.3057158873, 0.3302087162), Vector2(-0.414503978, 0.1751754899), Vector2(-0.3738139881, 0.2505256519), Vector2(0.2236891408, -0.3904653228), Vector2(0.002967775577, -0.4499902136), Vector2(0.1747128327, -0.4146991995), Vector2(-0.4423772489, -0.08247647938), Vector2(-0.2763960987, -0.355112935), Vector2(-0.4019385906, -0.2023496216), Vector2(0.3871414161, -0.2293938184), Vector2(-0.430008727, 0.1326367019), Vector2(-0.03037574274, -0.4489736231), Vector2(-0.3486181573, 0.2845441624), Vector2(0.04553517144, -0.4476902368), Vector2(-0.0375802926, 0.4484280562), Vector2(0.3266408905, 0.3095250049), Vector2(0.06540017593, -0.4452222108), Vector2(0.03409025829, 0.448706869), Vector2(-0.4449193635, 0.06742966669), Vector2(-0.4255936157, -0.1461850686), Vector2(0.449917292, 0.008627302568), Vector2(0.05242606404, 0.4469356864), Vector2(-0.4495305179, -0.02055026661), Vector2(-0.1204775703, 0.4335725488), Vector2(-0.341986385, -0.2924813028), Vector2(0.3865320182, 0.2304191809), Vector2(0.04506097811, -0.447738214), Vector2(-0.06283465979, 0.4455915232), Vector2(0.3932600341, -0.2187385324), Vector2(0.4472261803, -0.04988730975), Vector2(0.3753571011, -0.2482076684), Vector2(-0.273662295, 0.357223947), Vector2(0.1700461538, 0.4166344988), Vector2(0.4102692229, 0.1848760794), Vector2(0.323227187, -0.3130881435), Vector2(-0.2882310238, -0.3455761521), Vector2(0.2050972664, 0.4005435199), Vector2(0.4414085979, -0.08751256895), Vector2(-0.1684700334, 0.4172743077), Vector2(-0.003978032396, 0.4499824166), Vector2(-0.2055133639, 0.4003301853), Vector2(-0.006095674897, -0.4499587123), Vector2(-0.1196228124, -0.4338091548), Vector2(0.3901528491, -0.2242337048), Vector2(0.01723531752, 0.4496698165), Vector2(-0.3015070339, 0.3340561458), Vector2(-0.01514262423, -0.4497451511), Vector2(-0.4142574071, -0.1757577897), Vector2(-0.1916377265, -0.4071547394), Vector2(0.3749248747, 0.2488600778), Vector2(-0.2237774255, 0.3904147331), Vector2(-0.4166343106, -0.1700466149), Vector2(0.3619171625, 0.267424695), Vector2(0.1891126846, -0.4083336779), Vector2(-0.3127425077, 0.323561623), Vector2(-0.3281807787, 0.307891826), Vector2(-0.2294806661, 0.3870899429), Vector2(-0.3445266136, 0.2894847362), Vector2(-0.4167095422, -0.1698621719), Vector2(-0.257890321, -0.3687717212), Vector2(-0.3612037825, 0.2683874578), Vector2(0.2267996491, 0.3886668486), Vector2(0.207157062, 0.3994821043), Vector2(0.08355176718, -0.4421754202), Vector2(-0.4312233307, 0.1286329626), Vector2(0.3257055497, 0.3105090899), Vector2(0.177701095, -0.4134275279), Vector2(-0.445182522, 0.06566979625), Vector2(0.3955143435, 0.2146355146), Vector2(-0.4264613988, 0.1436338239), Vector2(-0.3793799665, -0.2420141339), Vector2(0.04617599081, -0.4476245948), Vector2(-0.371405428, -0.2540826796), Vector2(0.2563570295, -0.3698392535), Vector2(0.03476646309, 0.4486549822), Vector2(-0.3065454405, 0.3294387544), Vector2(-0.2256979823, 0.3893076172), Vector2(0.4116448463, -0.1817925206), Vector2(-0.2907745828, -0.3434387019), Vector2(0.2842278468, -0.348876097), Vector2(0.3114589359, -0.3247973695), Vector2(0.4464155859, -0.0566844308), Vector2(-0.3037334033, -0.3320331606), Vector2(0.4079607166, 0.1899159123), Vector2(-0.3486948919, -0.2844501228), Vector2(0.3264821436, 0.3096924441), Vector2(0.3211142406, 0.3152548881), Vector2(0.01183382662, 0.4498443737), Vector2(0.4333844092, 0.1211526057), Vector2(0.3118668416, 0.324405723), Vector2(-0.272753471, 0.3579183483), Vector2(-0.422228622, -0.1556373694), Vector2(-0.1009700099, -0.4385260051), Vector2(-0.2741171231, -0.3568750521), Vector2(-0.1465125133, 0.4254810025), Vector2(0.2302279044, -0.3866459777), Vector2(-0.3699435608, 0.2562064828), Vector2(0.105700352, -0.4374099171), Vector2(-0.2646713633, 0.3639355292), Vector2(0.3521828122, 0.2801200935), Vector2(-0.1864187807, -0.4095705534), Vector2(0.1994492955, -0.4033856449), Vector2(0.3937065066, 0.2179339044), Vector2(-0.3226158377, 0.3137180602), Vector2(0.3796235338, 0.2416318948), Vector2(0.1482921929, 0.4248640083), Vector2(-0.407400394, 0.1911149365), Vector2(0.4212853031, 0.1581729856), Vector2(-0.2621297173, 0.3657704353), Vector2(-0.2536986953, -0.3716678248), Vector2(-0.2100236383, 0.3979825013), Vector2(0.3624152444, 0.2667493029), Vector2(-0.3645038479, -0.2638881295), Vector2(0.2318486784, 0.3856762766), Vector2(-0.3260457004, 0.3101519002), Vector2(-0.2130045332, -0.3963950918), Vector2(0.3814998766, -0.2386584257), Vector2(-0.342977305, 0.2913186713), Vector2(-0.4355865605, 0.1129794154), Vector2(-0.2104679605, 0.3977477059), Vector2(0.3348364681, -0.3006402163), Vector2(0.3430468811, 0.2912367377), Vector2(-0.2291836801, -0.3872658529), Vector2(0.2547707298, -0.3709337882), Vector2(0.4236174945, -0.151816397), Vector2(-0.15387742, 0.4228731957), Vector2(-0.4407449312, 0.09079595574), Vector2(-0.06805276192, -0.444824484), Vector2(0.4453517192, -0.06451237284), Vector2(0.2562464609, -0.3699158705), Vector2(0.3278198355, -0.3082761026), Vector2(-0.4122774207, -0.1803533432), Vector2(0.3354090914, -0.3000012356), Vector2(0.446632869, -0.05494615882), Vector2(-0.1608953296, 0.4202531296), Vector2(-0.09463954939, 0.4399356268), Vector2(-0.02637688324, -0.4492262904), Vector2(0.447102804, -0.05098119915), Vector2(-0.4365670908, 0.1091291678), Vector2(-0.3959858651, 0.2137643437), Vector2(-0.4240048207, -0.1507312575), Vector2(-0.3882794568, 0.2274622243), Vector2(-0.4283652566, -0.1378521198), Vector2(0.3303888091, 0.305521251), Vector2(0.3321434919, -0.3036127481), Vector2(-0.413021046, -0.1786438231), Vector2(0.08403060337, -0.4420846725), Vector2(-0.3822882919, 0.2373934748), Vector2(-0.3712395594, -0.2543249683), Vector2(0.4472363971, -0.04979563372), Vector2(-0.4466591209, 0.05473234629), Vector2(0.0486272539, -0.4473649407), Vector2(-0.4203101295, -0.1607463688), Vector2(0.2205360833, 0.39225481), Vector2(-0.3624900666, 0.2666476169), Vector2(-0.4036086833, -0.1989975647), Vector2(0.2152727807, 0.3951678503), Vector2(-0.4359392962, -0.1116106179), Vector2(0.4178354266, 0.1670735057), Vector2(0.2007630161, 0.4027334247), Vector2(-0.07278067175, -0.4440754146), Vector2(0.3644748615, -0.2639281632), Vector2(-0.4317451775, 0.126870413), Vector2(-0.297436456, 0.3376855855), Vector2(-0.2998672222, 0.3355289094), Vector2(-0.2673674124, 0.3619594822), Vector2(0.2808423357, 0.3516071423), Vector2(0.3498946567, 0.2829730186), Vector2(-0.2229685561, 0.390877248), Vector2(0.3305823267, 0.3053118493), Vector2(-0.2436681211, -0.3783197679), Vector2(-0.03402776529, 0.4487116125), Vector2(-0.319358823, 0.3170330301), Vector2(0.4454633477, -0.06373700535), Vector2(0.4483504221, 0.03849544189), Vector2(-0.4427358436, -0.08052932871), Vector2(0.05452298565, 0.4466847255), Vector2(-0.2812560807, 0.3512762688), Vector2(0.1266696921, 0.4318041097), Vector2(-0.3735981243, 0.2508474468), Vector2(0.2959708351, -0.3389708908), Vector2(-0.3714377181, 0.254035473), Vector2(-0.404467102, -0.1972469604), Vector2(0.1636165687, -0.419201167), Vector2(0.3289185495, -0.3071035458), Vector2(-0.2494824991, -0.3745109914), Vector2(0.03283133272, 0.4488007393), Vector2(-0.166306057, -0.4181414777), Vector2(-0.106833179, 0.4371346153), Vector2(0.06440260376, -0.4453676062), Vector2(-0.4483230967, 0.03881238203), Vector2(-0.421377757, -0.1579265206), Vector2(0.05097920662, -0.4471030312), Vector2(0.2050584153, -0.4005634111), Vector2(0.4178098529, -0.167137449), Vector2(-0.3565189504, -0.2745801121), Vector2(0.4478398129, 0.04403977727), Vector2(-0.3399999602, -0.2947881053), Vector2(0.3767121994, 0.2461461331), Vector2(-0.3138934434, 0.3224451987), Vector2(-0.1462001792, -0.4255884251), Vector2(0.3970290489, -0.2118205239), Vector2(0.4459149305, -0.06049689889), Vector2(-0.4104889426, -0.1843877112), Vector2(0.1475103971, -0.4251360756), Vector2(0.09258030352, 0.4403735771), Vector2(-0.1589664637, -0.4209865359), Vector2(0.2482445008, 0.3753327428), Vector2(0.4383624232, -0.1016778537), Vector2(0.06242802956, 0.4456486745), Vector2(0.2846591015, -0.3485243118), Vector2(-0.344202744, -0.2898697484), Vector2(0.1198188883, -0.4337550392), Vector2(-0.243590703, 0.3783696201), Vector2(0.2958191174, -0.3391033025), Vector2(-0.1164007991, 0.4346847754), Vector2(0.1274037151, -0.4315881062), Vector2(0.368047306, 0.2589231171), Vector2(0.2451436949, 0.3773652989), Vector2(-0.4314509715, 0.12786735)) +private val CELL_3D = arrayOf(Vector3(0.1453787434, -0.4149781685, -0.0956981749), Vector3(-0.01242829687, -0.1457918398, -0.4255470325), Vector3(0.2877979582, -0.02606483451, -0.3449535616), Vector3(-0.07732986802, 0.2377094325, 0.3741848704), Vector3(0.1107205875, -0.3552302079, -0.2530858567), Vector3(0.2755209141, 0.2640521179, -0.238463215), Vector3(0.294168941, 0.1526064594, 0.3044271714), Vector3(0.4000921098, -0.2034056362, 0.03244149937), Vector3(-0.1697304074, 0.3970864695, -0.1265461359), Vector3(-0.1483224484, -0.3859694688, 0.1775613147), Vector3(0.2623596946, -0.2354852944, 0.2796677792), Vector3(-0.2709003183, 0.3505271138, -0.07901746678), Vector3(-0.03516550699, 0.3885234328, 0.2243054374), Vector3(-0.1267712655, 0.1920044036, 0.3867342179), Vector3(0.02952021915, 0.4409685861, 0.08470692262), Vector3(-0.2806854217, -0.266996757, 0.2289725438), Vector3(-0.171159547, 0.2141185563, 0.3568720405), Vector3(0.2113227183, 0.3902405947, -0.07453178509), Vector3(-0.1024352839, 0.2128044156, -0.3830421561), Vector3(-0.3304249877, -0.1566986703, 0.2622305365), Vector3(0.2091111325, 0.3133278055, -0.2461670583), Vector3(0.344678154, -0.1944240454, -0.2142341261), Vector3(0.1984478035, -0.3214342325, -0.2445373252), Vector3(-0.2929008603, 0.2262915116, 0.2559320961), Vector3(-0.1617332831, 0.006314769776, -0.4198838754), Vector3(-0.3582060271, -0.148303178, -0.2284613961), Vector3(-0.1852067326, -0.3454119342, -0.2211087107), Vector3(0.3046301062, 0.1026310383, 0.314908508), Vector3(-0.03816768434, -0.2551766358, -0.3686842991), Vector3(-0.4084952196, 0.1805950793, 0.05492788837), Vector3(-0.02687443361, -0.2749741471, 0.3551999201), Vector3(-0.03801098351, 0.3277859044, 0.3059600725), Vector3(0.2371120802, 0.2900386767, -0.2493099024), Vector3(0.4447660503, 0.03946930643, 0.05590469027), Vector3(0.01985147278, -0.01503183293, -0.4493105419), Vector3(0.4274339143, 0.03345994256, -0.1366772882), Vector3(-0.2072988631, 0.2871414597, -0.2776273824), Vector3(-0.3791240978, 0.1281177671, 0.2057929936), Vector3(-0.2098721267, -0.1007087278, -0.3851122467), Vector3(0.01582798878, 0.4263894424, 0.1429738373), Vector3(-0.1888129464, -0.3160996813, -0.2587096108), Vector3(0.1612988974, -0.1974805082, -0.3707885038), Vector3(-0.08974491322, 0.229148752, -0.3767448739), Vector3(0.07041229526, 0.4150230285, -0.1590534329), Vector3(-0.1082925611, -0.1586061639, 0.4069604477), Vector3(0.2474100658, -0.3309414609, 0.1782302128), Vector3(-0.1068836661, -0.2701644537, -0.3436379634), Vector3(0.2396452163, 0.06803600538, -0.3747549496), Vector3(-0.3063886072, 0.2597428179, 0.2028785103), Vector3(0.1593342891, -0.3114350249, -0.2830561951), Vector3(0.2709690528, 0.1412648683, -0.3303331794), Vector3(-0.1519780427, 0.3623355133, 0.2193527988), Vector3(0.1699773681, 0.3456012883, 0.2327390037), Vector3(-0.1986155616, 0.3836276443, -0.1260225743), Vector3(-0.1887482106, -0.2050154888, -0.353330953), Vector3(0.2659103394, 0.3015631259, -0.2021172246), Vector3(-0.08838976154, -0.4288819642, -0.1036702021), Vector3(-0.04201869311, 0.3099592485, 0.3235115047), Vector3(-0.3230334656, 0.201549922, -0.2398478873), Vector3(0.2612720941, 0.2759854499, -0.2409749453), Vector3(0.385713046, 0.2193460345, 0.07491837764), Vector3(0.07654967953, 0.3721732183, 0.241095919), Vector3(0.4317038818, -0.02577753072, 0.1243675091), Vector3(-0.2890436293, -0.3418179959, -0.04598084447), Vector3(-0.2201947582, 0.383023377, -0.08548310451), Vector3(0.4161322773, -0.1669634289, -0.03817251927), Vector3(0.2204718095, 0.02654238946, -0.391391981), Vector3(-0.1040307469, 0.3890079625, -0.2008741118), Vector3(-0.1432122615, 0.371614387, -0.2095065525), Vector3(0.3978380468, -0.06206669342, 0.2009293758), Vector3(-0.2599274663, 0.2616724959, -0.2578084893), Vector3(0.4032618332, -0.1124593585, 0.1650235939), Vector3(-0.08953470255, -0.3048244735, 0.3186935478), Vector3(0.118937202, -0.2875221847, 0.325092195), Vector3(0.02167047076, -0.03284630549, -0.4482761547), Vector3(-0.3411343612, 0.2500031105, 0.1537068389), Vector3(0.3162964612, 0.3082064153, -0.08640228117), Vector3(0.2355138889, -0.3439334267, -0.1695376245), Vector3(-0.02874541518, -0.3955933019, 0.2125550295), Vector3(-0.2461455173, 0.02020282325, -0.3761704803), Vector3(0.04208029445, -0.4470439576, 0.02968078139), Vector3(0.2727458746, 0.2288471896, -0.2752065618), Vector3(-0.1347522818, -0.02720848277, -0.4284874806), Vector3(0.3829624424, 0.1231931484, -0.2016512234), Vector3(-0.3547613644, 0.1271702173, 0.2459107769), Vector3(0.2305790207, 0.3063895591, 0.2354968222), Vector3(-0.08323845599, -0.1922245118, 0.3982726409), Vector3(0.2993663085, -0.2619918095, -0.2103333191), Vector3(-0.2154865723, 0.2706747713, 0.287751117), Vector3(0.01683355354, -0.2680655787, -0.3610505186), Vector3(0.05240429123, 0.4335128183, -0.1087217856), Vector3(0.00940104872, -0.4472890582, 0.04841609928), Vector3(0.3465688735, 0.01141914583, -0.2868093776), Vector3(-0.3706867948, -0.2551104378, 0.003156692623), Vector3(0.2741169781, 0.2139972417, -0.2855959784), Vector3(0.06413433865, 0.1708718512, 0.4113266307), Vector3(-0.388187972, -0.03973280434, -0.2241236325), Vector3(0.06419469312, -0.2803682491, 0.3460819069), Vector3(-0.1986120739, -0.3391173584, 0.2192091725), Vector3(-0.203203009, -0.3871641506, 0.1063600375), Vector3(-0.1389736354, -0.2775901578, -0.3257760473), Vector3(-0.06555641638, 0.342253257, -0.2847192729), Vector3(-0.2529246486, -0.2904227915, 0.2327739768), Vector3(0.1444476522, 0.1069184044, 0.4125570634), Vector3(-0.3643780054, -0.2447099973, -0.09922543227), Vector3(0.4286142488, -0.1358496089, -0.01829506817), Vector3(0.165872923, -0.3136808464, -0.2767498872), Vector3(0.2219610524, -0.3658139958, 0.1393320198), Vector3(0.04322940318, -0.3832730794, 0.2318037215), Vector3(-0.08481269795, -0.4404869674, -0.03574965489), Vector3(0.1822082075, -0.3953259299, 0.1140946023), Vector3(-0.3269323334, 0.3036542563, 0.05838957105), Vector3(-0.4080485344, 0.04227858267, -0.184956522), Vector3(0.2676025294, -0.01299671652, 0.36155217), Vector3(0.3024892441, -0.1009990293, -0.3174892964), Vector3(0.1448494052, 0.425921681, -0.0104580805), Vector3(0.4198402157, 0.08062320474, 0.1404780841), Vector3(-0.3008872161, -0.333040905, -0.03241355801), Vector3(0.3639310428, -0.1291284382, -0.2310412139), Vector3(0.3295806598, 0.0184175994, -0.3058388149), Vector3(0.2776259487, -0.2974929052, -0.1921504723), Vector3(0.4149000507, -0.144793182, -0.09691688386), Vector3(0.145016715, -0.0398992945, 0.4241205002), Vector3(0.09299023471, -0.299732164, -0.3225111565), Vector3(0.1028907093, -0.361266869, 0.247789732), Vector3(0.2683057049, -0.07076041213, -0.3542668666), Vector3(-0.4227307273, -0.07933161816, -0.1323073187), Vector3(-0.1781224702, 0.1806857196, -0.3716517945), Vector3(0.4390788626, -0.02841848598, -0.09435116353), Vector3(0.2972583585, 0.2382799621, -0.2394997452), Vector3(-0.1707002821, 0.2215845691, 0.3525077196), Vector3(0.3806686614, 0.1471852559, -0.1895464869), Vector3(-0.1751445661, -0.274887877, 0.3102596268), Vector3(-0.2227237566, -0.2316778837, 0.3149912482), Vector3(0.1369633021, 0.1341343041, -0.4071228836), Vector3(-0.3529503428, -0.2472893463, -0.129514612), Vector3(-0.2590744185, -0.2985577559, -0.2150435121), Vector3(-0.3784019401, 0.2199816631, -0.1044989934), Vector3(-0.05635805671, 0.1485737441, 0.4210102279), Vector3(0.3251428613, 0.09666046873, -0.2957006485), Vector3(-0.4190995804, 0.1406751354, -0.08405978803), Vector3(-0.3253150961, -0.3080335042, -0.04225456877), Vector3(0.2857945863, -0.05796152095, 0.3427271751), Vector3(-0.2733604046, 0.1973770973, -0.2980207554), Vector3(0.219003657, 0.2410037886, -0.3105713639), Vector3(0.3182767252, -0.271342949, 0.1660509868), Vector3(-0.03222023115, -0.3331161506, -0.300824678), Vector3(-0.3087780231, 0.1992794134, -0.2596995338), Vector3(-0.06487611647, -0.4311322747, 0.1114273361), Vector3(0.3921171432, -0.06294284106, -0.2116183942), Vector3(-0.1606404506, -0.358928121, -0.2187812825), Vector3(-0.03767771199, -0.2290351443, 0.3855169162), Vector3(0.1394866832, -0.3602213994, 0.2308332918), Vector3(-0.4345093872, 0.005751117145, 0.1169124335), Vector3(-0.1044637494, 0.4168128432, -0.1336202785), Vector3(0.2658727501, 0.2551943237, 0.2582393035), Vector3(0.2051461999, 0.1975390727, 0.3484154868), Vector3(-0.266085566, 0.23483312, 0.2766800993), Vector3(0.07849405464, -0.3300346342, -0.2956616708), Vector3(-0.2160686338, 0.05376451292, -0.3910546287), Vector3(-0.185779186, 0.2148499206, 0.3490352499), Vector3(0.02492421743, -0.3229954284, -0.3123343347), Vector3(-0.120167831, 0.4017266681, 0.1633259825), Vector3(-0.02160084693, -0.06885389554, 0.4441762538), Vector3(0.2597670064, 0.3096300784, 0.1978643903), Vector3(-0.1611553854, -0.09823036005, 0.4085091653), Vector3(-0.3278896792, 0.1461670309, 0.2713366126), Vector3(0.2822734956, 0.03754421121, -0.3484423997), Vector3(0.03169341113, 0.347405252, -0.2842624114), Vector3(0.2202613604, -0.3460788041, -0.1849713341), Vector3(0.2933396046, 0.3031973659, 0.1565989581), Vector3(-0.3194922995, 0.2453752201, -0.200538455), Vector3(-0.3441586045, -0.1698856132, -0.2349334659), Vector3(0.2703645948, -0.3574277231, 0.04060059933), Vector3(0.2298568861, 0.3744156221, 0.0973588921), Vector3(0.09326603877, -0.3170108894, 0.3054595587), Vector3(-0.1116165319, -0.2985018719, 0.3177080142), Vector3(0.2172907365, -0.3460005203, -0.1885958001), Vector3(0.1991339479, 0.3820341668, -0.1299829458), Vector3(-0.0541918155, -0.2103145071, 0.39412061), Vector3(0.08871336998, 0.2012117383, 0.3926114802), Vector3(0.2787673278, 0.3505404674, 0.04370535101), Vector3(-0.322166438, 0.3067213525, 0.06804996813), Vector3(-0.4277366384, 0.132066775, 0.04582286686), Vector3(0.240131882, -0.1612516055, 0.344723946), Vector3(0.1448607981, -0.2387819045, 0.3528435224), Vector3(-0.3837065682, -0.2206398454, 0.08116235683), Vector3(-0.4382627882, -0.09082753406, -0.04664855374), Vector3(-0.37728353, 0.05445141085, 0.2391488697), Vector3(0.1259579313, 0.348394558, 0.2554522098), Vector3(-0.1406285511, -0.270877371, -0.3306796947), Vector3(-0.1580694418, 0.4162931958, -0.06491553533), Vector3(0.2477612106, -0.2927867412, -0.2353514536), Vector3(0.2916132853, 0.3312535401, 0.08793624968), Vector3(0.07365265219, -0.1666159848, 0.411478311), Vector3(-0.26126526, -0.2422237692, 0.2748965434), Vector3(-0.3721862032, 0.252790166, 0.008634938242), Vector3(-0.3691191571, -0.255281188, 0.03290232422), Vector3(0.2278441737, -0.3358364886, 0.1944244981), Vector3(0.363398169, -0.2310190248, 0.1306597909), Vector3(-0.304231482, -0.2698452035, 0.1926830856), Vector3(-0.3199312232, 0.316332536, -0.008816977938), Vector3(0.2874852279, 0.1642275508, -0.304764754), Vector3(-0.1451096801, 0.3277541114, -0.2720669462), Vector3(0.3220090754, 0.0511344108, 0.3101538769), Vector3(-0.1247400865, -0.04333605335, -0.4301882115), Vector3(-0.2829555867, -0.3056190617, -0.1703910946), Vector3(0.1069384374, 0.3491024667, -0.2630430352), Vector3(-0.1420661144, -0.3055376754, -0.2982682484), Vector3(-0.250548338, 0.3156466809, -0.2002316239), Vector3(0.3265787872, 0.1871229129, 0.2466400438), Vector3(0.07646097258, -0.3026690852, 0.324106687), Vector3(0.3451771584, 0.2757120714, -0.0856480183), Vector3(0.298137964, 0.2852657134, 0.179547284), Vector3(0.2812250376, 0.3466716415, 0.05684409612), Vector3(0.4390345476, -0.09790429955, -0.01278335452), Vector3(0.2148373234, 0.1850172527, 0.3494474791), Vector3(0.2595421179, -0.07946825393, 0.3589187731), Vector3(0.3182823114, -0.307355516, -0.08203022006), Vector3(-0.4089859285, -0.04647718411, 0.1818526372), Vector3(-0.2826749061, 0.07417482322, 0.3421885344), Vector3(0.3483864637, 0.225442246, -0.1740766085), Vector3(-0.3226415069, -0.1420585388, -0.2796816575), Vector3(0.4330734858, -0.118868561, -0.02859407492), Vector3(-0.08717822568, -0.3909896417, -0.2050050172), Vector3(-0.2149678299, 0.3939973956, -0.03247898316), Vector3(-0.2687330705, 0.322686276, -0.1617284888), Vector3(0.2105665099, -0.1961317136, -0.3459683451), Vector3(0.4361845915, -0.1105517485, 0.004616608544), Vector3(0.05333333359, -0.313639498, -0.3182543336), Vector3(-0.05986216652, 0.1361029153, -0.4247264031), Vector3(0.3664988455, 0.2550543014, -0.05590974511), Vector3(-0.2341015558, -0.182405731, 0.3382670703), Vector3(-0.04730947785, -0.4222150243, -0.1483114513), Vector3(-0.2391566239, -0.2577696514, -0.2808182972), Vector3(-0.1242081035, 0.4256953395, -0.07652336246), Vector3(0.2614832715, -0.3650179274, 0.02980623099), Vector3(-0.2728794681, -0.3499628774, 0.07458404908), Vector3(0.007892900508, -0.1672771315, 0.4176793787), Vector3(-0.01730330376, 0.2978486637, -0.3368779738), Vector3(0.2054835762, -0.3252600376, -0.2334146693), Vector3(-0.3231994983, 0.1564282844, -0.2712420987), Vector3(-0.2669545963, 0.2599343665, -0.2523278991), Vector3(-0.05554372779, 0.3170813944, -0.3144428146), Vector3(-0.2083935713, -0.310922837, -0.2497981362), Vector3(0.06989323478, -0.3156141536, 0.3130537363), Vector3(0.3847566193, -0.1605309138, -0.1693876312), Vector3(-0.3026215288, -0.3001537679, -0.1443188342), Vector3(0.3450735512, 0.08611519592, 0.2756962409), Vector3(0.1814473292, -0.2788782453, -0.3029914042), Vector3(-0.03855010448, 0.09795110726, 0.4375151083), Vector3(0.3533670318, 0.2665752752, 0.08105160988), Vector3(-0.007945601311, 0.140359426, -0.4274764309), Vector3(0.4063099273, -0.1491768253, -0.1231199324), Vector3(-0.2016773589, 0.008816271194, -0.4021797064), Vector3(-0.07527055435, -0.425643481, -0.1251477955)) diff --git a/orx-noise/src/main/kotlin/Interpolation.kt b/orx-noise/src/main/kotlin/Interpolation.kt index bf68e1334..10ee5f823 100644 --- a/orx-noise/src/main/kotlin/Interpolation.kt +++ b/orx-noise/src/main/kotlin/Interpolation.kt @@ -1,24 +1,24 @@ -package org.openrndr.extra.noise - - - -fun hermite(t: Double): Double { - return t * t * (3 - 2 * t) -} - -fun quintic(t: Double): Double { - return t * t * t * (t * (t * 6 - 15) + 10) -} - -fun cubic(a: Double, b: Double, c: Double, d: Double, t: Double) : Double { - val p = d - c - (a - b) - return t * t * t * p + t * t * (a - b - p) + t * (c - a) + b -} - -fun linear(x: Double) : Double { - return x -} - -fun lerp(left: Double, right: Double, x: Double): Double { - return left * (1.0 - x) + right * x +package org.openrndr.extra.noise + + + +fun hermite(t: Double): Double { + return t * t * (3 - 2 * t) +} + +fun quintic(t: Double): Double { + return t * t * t * (t * (t * 6 - 15) + 10) +} + +fun cubic(a: Double, b: Double, c: Double, d: Double, t: Double) : Double { + val p = d - c - (a - b) + return t * t * t * p + t * t * (a - b - p) + t * (c - a) + b +} + +fun linear(x: Double) : Double { + return x +} + +fun lerp(left: Double, right: Double, x: Double): Double { + return left * (1.0 - x) + right * x } \ No newline at end of file diff --git a/orx-noise/src/main/kotlin/MathUtils.kt b/orx-noise/src/main/kotlin/MathUtils.kt index b0f3a5a4c..71ceafd1d 100644 --- a/orx-noise/src/main/kotlin/MathUtils.kt +++ b/orx-noise/src/main/kotlin/MathUtils.kt @@ -1,6 +1,6 @@ -package org.openrndr.extra.noise - - -fun Double.fastFloor(): Int { - return if (this >= 0) this.toInt() else this.toInt() - 1 +package org.openrndr.extra.noise + + +fun Double.fastFloor(): Int { + return if (this >= 0) this.toInt() else this.toInt() - 1 } \ No newline at end of file diff --git a/orx-noise/src/main/kotlin/PerlinNoise2D.kt b/orx-noise/src/main/kotlin/PerlinNoise2D.kt index 23a3ceeb1..0398ba796 100644 --- a/orx-noise/src/main/kotlin/PerlinNoise2D.kt +++ b/orx-noise/src/main/kotlin/PerlinNoise2D.kt @@ -1,26 +1,26 @@ -package org.openrndr.extra.noise - -fun perlinLinear(seed: Int, x: Double, y: Double) = perlin(seed, x, y, ::linear) -fun perlinQuintic(seed: Int, x: Double, y: Double) = perlin(seed, x, y, ::quintic) -fun perlinHermite(seed: Int, x: Double, y: Double) = perlin(seed, x, y, ::hermite) - -private fun perlin(seed: Int, x: Double, y: Double, interpolator: (Double) -> Double): Double { - val x0 = x.fastFloor() - val y0 = y.fastFloor() - val x1 = x0 + 1 - val y1 = y0 + 1 - - val xs = interpolator(x - x0) - val ys = interpolator(y - y0) - - - val xd0 = x - x0 - val yd0 = y - y0 - val xd1 = xd0 - 1 - val yd1 = yd0 - 1 - - val xf0 = lerp(gradCoord2D(seed, x0, y0, xd0, yd0), gradCoord2D(seed, x1, y0, xd1, yd0), xs) - val xf1 = lerp(gradCoord2D(seed, x0, y1, xd0, yd1), gradCoord2D(seed, x1, y1, xd1, yd1), xs) - - return lerp(xf0, xf1, ys) +package org.openrndr.extra.noise + +fun perlinLinear(seed: Int, x: Double, y: Double) = perlin(seed, x, y, ::linear) +fun perlinQuintic(seed: Int, x: Double, y: Double) = perlin(seed, x, y, ::quintic) +fun perlinHermite(seed: Int, x: Double, y: Double) = perlin(seed, x, y, ::hermite) + +private fun perlin(seed: Int, x: Double, y: Double, interpolator: (Double) -> Double): Double { + val x0 = x.fastFloor() + val y0 = y.fastFloor() + val x1 = x0 + 1 + val y1 = y0 + 1 + + val xs = interpolator(x - x0) + val ys = interpolator(y - y0) + + + val xd0 = x - x0 + val yd0 = y - y0 + val xd1 = xd0 - 1 + val yd1 = yd0 - 1 + + val xf0 = lerp(gradCoord2D(seed, x0, y0, xd0, yd0), gradCoord2D(seed, x1, y0, xd1, yd0), xs) + val xf1 = lerp(gradCoord2D(seed, x0, y1, xd0, yd1), gradCoord2D(seed, x1, y1, xd1, yd1), xs) + + return lerp(xf0, xf1, ys) } \ No newline at end of file diff --git a/orx-noise/src/main/kotlin/PerlinNoise3D.kt b/orx-noise/src/main/kotlin/PerlinNoise3D.kt index f07dbafa9..d2eb43c91 100644 --- a/orx-noise/src/main/kotlin/PerlinNoise3D.kt +++ b/orx-noise/src/main/kotlin/PerlinNoise3D.kt @@ -1,35 +1,35 @@ -package org.openrndr.extra.noise - -fun perlinLinear(seed: Int, x: Double, y: Double, z: Double) = perlin(seed, x, y, z, ::linear) -fun perlinQuintic(seed: Int, x: Double, y: Double, z: Double) = perlin(seed, x, y, z, ::quintic) -fun perlinHermite(seed: Int, x: Double, y: Double, z: Double) = perlin(seed, x, y, z, ::hermite) - -inline fun perlin(seed: Int, x: Double, y: Double, z: Double, crossinline interpolator: (Double) -> Double = ::linear): Double { - val x0 = x.fastFloor() - val y0 = y.fastFloor() - val z0 = z.fastFloor() - val x1 = x0 + 1 - val y1 = y0 + 1 - val z1 = z0 + 1 - - val xs: Double = interpolator(x - x0) - val ys: Double = interpolator(y - y0) - val zs: Double = interpolator(z - z0) - - val xd0 = x - x0 - val yd0 = y - y0 - val zd0 = z - z0 - val xd1 = xd0 - 1 - val yd1 = yd0 - 1 - val zd1 = zd0 - 1 - - val xf00 = lerp(gradCoord3D(seed, x0, y0, z0, xd0, yd0, zd0), gradCoord3D(seed, x1, y0, z0, xd1, yd0, zd0), xs) - val xf10 = lerp(gradCoord3D(seed, x0, y1, z0, xd0, yd1, zd0), gradCoord3D(seed, x1, y1, z0, xd1, yd1, zd0), xs) - val xf01 = lerp(gradCoord3D(seed, x0, y0, z1, xd0, yd0, zd1), gradCoord3D(seed, x1, y0, z1, xd1, yd0, zd1), xs) - val xf11 = lerp(gradCoord3D(seed, x0, y1, z1, xd0, yd1, zd1), gradCoord3D(seed, x1, y1, z1, xd1, yd1, zd1), xs) - - val yf0 = lerp(xf00, xf10, ys) - val yf1 = lerp(xf01, xf11, ys) - - return lerp(yf0, yf1, zs) +package org.openrndr.extra.noise + +fun perlinLinear(seed: Int, x: Double, y: Double, z: Double) = perlin(seed, x, y, z, ::linear) +fun perlinQuintic(seed: Int, x: Double, y: Double, z: Double) = perlin(seed, x, y, z, ::quintic) +fun perlinHermite(seed: Int, x: Double, y: Double, z: Double) = perlin(seed, x, y, z, ::hermite) + +inline fun perlin(seed: Int, x: Double, y: Double, z: Double, crossinline interpolator: (Double) -> Double = ::linear): Double { + val x0 = x.fastFloor() + val y0 = y.fastFloor() + val z0 = z.fastFloor() + val x1 = x0 + 1 + val y1 = y0 + 1 + val z1 = z0 + 1 + + val xs: Double = interpolator(x - x0) + val ys: Double = interpolator(y - y0) + val zs: Double = interpolator(z - z0) + + val xd0 = x - x0 + val yd0 = y - y0 + val zd0 = z - z0 + val xd1 = xd0 - 1 + val yd1 = yd0 - 1 + val zd1 = zd0 - 1 + + val xf00 = lerp(gradCoord3D(seed, x0, y0, z0, xd0, yd0, zd0), gradCoord3D(seed, x1, y0, z0, xd1, yd0, zd0), xs) + val xf10 = lerp(gradCoord3D(seed, x0, y1, z0, xd0, yd1, zd0), gradCoord3D(seed, x1, y1, z0, xd1, yd1, zd0), xs) + val xf01 = lerp(gradCoord3D(seed, x0, y0, z1, xd0, yd0, zd1), gradCoord3D(seed, x1, y0, z1, xd1, yd0, zd1), xs) + val xf11 = lerp(gradCoord3D(seed, x0, y1, z1, xd0, yd1, zd1), gradCoord3D(seed, x1, y1, z1, xd1, yd1, zd1), xs) + + val yf0 = lerp(xf00, xf10, ys) + val yf1 = lerp(xf01, xf11, ys) + + return lerp(yf0, yf1, zs) } \ No newline at end of file diff --git a/orx-noise/src/main/kotlin/SimplexNoise2D.kt b/orx-noise/src/main/kotlin/SimplexNoise2D.kt index a61b35c65..880ab52dd 100644 --- a/orx-noise/src/main/kotlin/SimplexNoise2D.kt +++ b/orx-noise/src/main/kotlin/SimplexNoise2D.kt @@ -1,63 +1,63 @@ -package org.openrndr.extra.noise - - -private val G2 = 1.0 / 4.0 -private val F2 = 1.0 / 2.0 - -fun simplex(seed: Int, x: Double, y: Double): Double { - var t = (x + y) * F2 - val i = (x + t).fastFloor() - val j = (y + t).fastFloor() - - t = ((i + j) * G2) - val X0 = i - t - val Y0 = j - t - - val x0 = x - X0 - val y0 = y - Y0 - - val i1: Int - val j1: Int - if (x0 > y0) { - i1 = 1 - j1 = 0 - } else { - i1 = 0 - j1 = 1 - } - - val x1 = x0 - i1 + G2 - val y1 = y0 - j1 + G2 - val x2 = x0 - 1 + F2 - val y2 = y0 - 1 + F2 - - val n0: Double - val n1: Double - val n2: Double - - t = 0.5 - x0 * x0 - y0 * y0 - if (t < 0) - n0 = 0.0 - else { - t *= t - n0 = t * t * gradCoord2D(seed, i, j, x0, y0) - } - - t = 0.5 - x1 * x1 - y1 * y1 - if (t < 0) - n1 = 0.0 - else { - t *= t - n1 = t * t * gradCoord2D(seed, i + i1, j + j1, x1, y1) - } - - t = 0.5 - x2 * x2 - y2 * y2 - if (t < 0) - n2 = 0.0 - else { - t *= t - n2 = t * t * gradCoord2D(seed, i + 1, j + 1, x2, y2) - } - - return 50.0 * (n0 + n1 + n2) +package org.openrndr.extra.noise + + +private val G2 = 1.0 / 4.0 +private val F2 = 1.0 / 2.0 + +fun simplex(seed: Int, x: Double, y: Double): Double { + var t = (x + y) * F2 + val i = (x + t).fastFloor() + val j = (y + t).fastFloor() + + t = ((i + j) * G2) + val X0 = i - t + val Y0 = j - t + + val x0 = x - X0 + val y0 = y - Y0 + + val i1: Int + val j1: Int + if (x0 > y0) { + i1 = 1 + j1 = 0 + } else { + i1 = 0 + j1 = 1 + } + + val x1 = x0 - i1 + G2 + val y1 = y0 - j1 + G2 + val x2 = x0 - 1 + F2 + val y2 = y0 - 1 + F2 + + val n0: Double + val n1: Double + val n2: Double + + t = 0.5 - x0 * x0 - y0 * y0 + if (t < 0) + n0 = 0.0 + else { + t *= t + n0 = t * t * gradCoord2D(seed, i, j, x0, y0) + } + + t = 0.5 - x1 * x1 - y1 * y1 + if (t < 0) + n1 = 0.0 + else { + t *= t + n1 = t * t * gradCoord2D(seed, i + i1, j + j1, x1, y1) + } + + t = 0.5 - x2 * x2 - y2 * y2 + if (t < 0) + n2 = 0.0 + else { + t *= t + n2 = t * t * gradCoord2D(seed, i + 1, j + 1, x2, y2) + } + + return 50.0 * (n0 + n1 + n2) } \ No newline at end of file diff --git a/orx-noise/src/main/kotlin/SimplexNoise3D.kt b/orx-noise/src/main/kotlin/SimplexNoise3D.kt index af718c926..7afb4ffab 100644 --- a/orx-noise/src/main/kotlin/SimplexNoise3D.kt +++ b/orx-noise/src/main/kotlin/SimplexNoise3D.kt @@ -1,94 +1,94 @@ -package org.openrndr.extra.noise - -fun simplex(seed: Int, x: Double, y: Double, z: Double): Double { - - var t = (x + y + z) / 3.0 - val i = (x + t).fastFloor() - val j = (y + t).fastFloor() - val k = (z + t).fastFloor() - - val t2 = (i + j + k) / 6.0 - val x0 = x - (i - t2) - val y0 = y - (j - t2) - val z0 = z - (k - t2) - - val i1: Int - val j1: Int - val k1: Int - - val i2: Int - val j2: Int - val k2: Int - - if (x0 >= y0) { - when { - y0 >= z0 -> { - i1 = 1; j1 = 0; k1 = 0; i2 = 1; j2 = 1; k2 = 0; } - x0 >= z0 -> { - i1 = 1; j1 = 0; k1 = 0; i2 = 1; j2 = 0; k2 = 1; } - else -> { - i1 = 0; j1 = 0; k1 = 1; i2 = 1; j2 = 0; k2 = 1; } - } - } else { - when { - y0 < z0 -> { - i1 = 0; j1 = 0; k1 = 1; i2 = 0; j2 = 1; k2 = 1; } - x0 < z0 -> { - i1 = 0; j1 = 1; k1 = 0; i2 = 0; j2 = 1; k2 = 1; } - else -> { - i1 = 0; j1 = 1; k1 = 0; i2 = 1; j2 = 1; k2 = 0; } - } - } - val x1 = x0 - i1 + 1.0 / 6.0 - val y1 = y0 - j1 + 1.0 / 6.0 - val z1 = z0 - k1 + 1.0 / 6.0 - val x2 = x0 - i2 + 1.0 / 3.0 - val y2 = y0 - j2 + 1.0 / 3.0 - val z2 = z0 - k2 + 1.0 / 3.0 - val x3 = x0 + ((1.0 / 6.0) * 3.0 - 1.0) - val y3 = y0 + ((1.0 / 6.0) * 3.0 - 1.0) - val z3 = z0 + ((1.0 / 6.0) * 3.0 - 1.0) - - val n0: Double - run { - var t = 0.6 * x0 * x0 - y0 * y0 - z0 * z0 - if (t < 0) { - n0 = 0.0 - } else { - t *= t - n0 = t * t * gradCoord3D(seed, i, j, k, x0, y0, z0) - } - } - val n1: Double - run { - var t = 0.6 * x1 * x1 - y1 * y1 - z1 * z1 - if (t < 0) { - n1 = 0.0 - } else { - t *= t - n1 = t * t * gradCoord3D(seed, i + i1, j + j1, k + k1, x1, y1, z1) - } - } - val n2: Double - run { - var t = 0.6 * x2 * x2 - y2 * y2 - z2 * z2 - if (t < 0) { - n2 = 0.0 - } else { - t *= t - n2 = t * t * gradCoord3D(seed, i + i2, j + j2, k + k2, x2, y2, z2) - } - } - - val n3: Double - run { - var t = 0.6 - x3 * x3 - y3 * y3 - z3 * z3 - if (t < 0) - n3 = 0.0 - else { - t *= t - n3 = t * t * gradCoord3D(seed, i + 1, j + 1, k + 1, x3, y3, z3) - } - } - return 32 * (n0 + n1 + n2 + n3) +package org.openrndr.extra.noise + +fun simplex(seed: Int, x: Double, y: Double, z: Double): Double { + + var t = (x + y + z) / 3.0 + val i = (x + t).fastFloor() + val j = (y + t).fastFloor() + val k = (z + t).fastFloor() + + val t2 = (i + j + k) / 6.0 + val x0 = x - (i - t2) + val y0 = y - (j - t2) + val z0 = z - (k - t2) + + val i1: Int + val j1: Int + val k1: Int + + val i2: Int + val j2: Int + val k2: Int + + if (x0 >= y0) { + when { + y0 >= z0 -> { + i1 = 1; j1 = 0; k1 = 0; i2 = 1; j2 = 1; k2 = 0; } + x0 >= z0 -> { + i1 = 1; j1 = 0; k1 = 0; i2 = 1; j2 = 0; k2 = 1; } + else -> { + i1 = 0; j1 = 0; k1 = 1; i2 = 1; j2 = 0; k2 = 1; } + } + } else { + when { + y0 < z0 -> { + i1 = 0; j1 = 0; k1 = 1; i2 = 0; j2 = 1; k2 = 1; } + x0 < z0 -> { + i1 = 0; j1 = 1; k1 = 0; i2 = 0; j2 = 1; k2 = 1; } + else -> { + i1 = 0; j1 = 1; k1 = 0; i2 = 1; j2 = 1; k2 = 0; } + } + } + val x1 = x0 - i1 + 1.0 / 6.0 + val y1 = y0 - j1 + 1.0 / 6.0 + val z1 = z0 - k1 + 1.0 / 6.0 + val x2 = x0 - i2 + 1.0 / 3.0 + val y2 = y0 - j2 + 1.0 / 3.0 + val z2 = z0 - k2 + 1.0 / 3.0 + val x3 = x0 + ((1.0 / 6.0) * 3.0 - 1.0) + val y3 = y0 + ((1.0 / 6.0) * 3.0 - 1.0) + val z3 = z0 + ((1.0 / 6.0) * 3.0 - 1.0) + + val n0: Double + run { + var t = 0.6 * x0 * x0 - y0 * y0 - z0 * z0 + if (t < 0) { + n0 = 0.0 + } else { + t *= t + n0 = t * t * gradCoord3D(seed, i, j, k, x0, y0, z0) + } + } + val n1: Double + run { + var t = 0.6 * x1 * x1 - y1 * y1 - z1 * z1 + if (t < 0) { + n1 = 0.0 + } else { + t *= t + n1 = t * t * gradCoord3D(seed, i + i1, j + j1, k + k1, x1, y1, z1) + } + } + val n2: Double + run { + var t = 0.6 * x2 * x2 - y2 * y2 - z2 * z2 + if (t < 0) { + n2 = 0.0 + } else { + t *= t + n2 = t * t * gradCoord3D(seed, i + i2, j + j2, k + k2, x2, y2, z2) + } + } + + val n3: Double + run { + var t = 0.6 - x3 * x3 - y3 * y3 - z3 * z3 + if (t < 0) + n3 = 0.0 + else { + t *= t + n3 = t * t * gradCoord3D(seed, i + 1, j + 1, k + 1, x3, y3, z3) + } + } + return 32 * (n0 + n1 + n2 + n3) } \ No newline at end of file diff --git a/orx-noise/src/main/kotlin/UniformRandom.kt b/orx-noise/src/main/kotlin/UniformRandom.kt index 05e9f0b7c..e621b74a7 100644 --- a/orx-noise/src/main/kotlin/UniformRandom.kt +++ b/orx-noise/src/main/kotlin/UniformRandom.kt @@ -1,71 +1,71 @@ -package org.openrndr.extra.noise - -import org.openrndr.math.Vector2 -import org.openrndr.math.Vector3 -import org.openrndr.math.Vector4 - - -fun Double.Companion.uniform(min: Double = -1.0, max: Double = 1.0): Double { - return (Math.random() * (max - min)) + min -} - -fun Vector2.Companion.uniform(min: Vector2 = -ONE, max: Vector2 = ONE): Vector2 { - return Vector2(Double.uniform(min.x, max.x), Double.uniform(min.y, max.y)) -} - -fun Vector2.Companion.uniform(min: Double = -1.0, max: Double = 1.0) = - Vector2.uniform(Vector2(min, min), Vector2(max, max)) - -fun Vector2.Companion.uniformRing(innerRadius: Double = 0.0, outerRadius: Double = 1.0): Vector2 { - while (true) { - uniform(-outerRadius, outerRadius).let { - val squaredLength = it.squaredLength - if (squaredLength >= innerRadius * innerRadius && squaredLength < outerRadius * outerRadius) { - return it - } - } - } -} - -fun Vector3.Companion.uniform(min: Double = -1.0, max: Double = 1.0): Vector3 = - Vector3.uniform(Vector3(min, min, min), Vector3(max, max, max)) - -fun Vector3.Companion.uniform(min: Vector3 = -ONE, max: Vector3 = ONE): Vector3 { - return Vector3(Double.uniform(min.x, max.x), Double.uniform(min.y, max.y), Double.uniform(min.z, max.z)) -} - -// squared length 'polyfill' for OPENRNDR 0.3.30 -private val Vector3.squaredLength__: Double get() = x * x + y * y + z * z - -fun Vector3.Companion.uniformRing(innerRadius: Double = 0.0, outerRadius: Double = 1.0): Vector3 { - while (true) { - uniform(-outerRadius, outerRadius).let { - val squaredLength = it.squaredLength__ - if (squaredLength >= innerRadius * innerRadius && squaredLength < outerRadius * outerRadius) { - return it - } - } - } -} - -// squared length 'polyfill' for OPENRNDR 0.3.30 -private val Vector4.squaredLength__: Double get() = x * x + y * y + z * z + w * w - -fun Vector4.Companion.uniform(min: Double = -1.0, max: Double = 1.0): Vector4 = - Vector4.uniform(Vector4(min, min, min, min), Vector4(max, max,max, max)) - -fun Vector4.Companion.uniform(min: Vector4 = -ONE, max: Vector4 = ONE): Vector4 { - return Vector4(Double.uniform(min.x, max.x), Double.uniform(min.y, max.y), Double.uniform(min.z, max.z), Double.uniform(min.w, max.w)) -} - -fun Vector4.Companion.uniformRing(innerRadius: Double = 0.0, outerRadius: Double = 1.0): Vector4 { - while (true) { - uniform(-outerRadius, outerRadius).let { - val squaredLength = it.squaredLength__ - if (squaredLength >= innerRadius * innerRadius && squaredLength < outerRadius * outerRadius) { - return it - } - } - } -} - +package org.openrndr.extra.noise + +import org.openrndr.math.Vector2 +import org.openrndr.math.Vector3 +import org.openrndr.math.Vector4 + + +fun Double.Companion.uniform(min: Double = -1.0, max: Double = 1.0): Double { + return (Math.random() * (max - min)) + min +} + +fun Vector2.Companion.uniform(min: Vector2 = -ONE, max: Vector2 = ONE): Vector2 { + return Vector2(Double.uniform(min.x, max.x), Double.uniform(min.y, max.y)) +} + +fun Vector2.Companion.uniform(min: Double = -1.0, max: Double = 1.0) = + Vector2.uniform(Vector2(min, min), Vector2(max, max)) + +fun Vector2.Companion.uniformRing(innerRadius: Double = 0.0, outerRadius: Double = 1.0): Vector2 { + while (true) { + uniform(-outerRadius, outerRadius).let { + val squaredLength = it.squaredLength + if (squaredLength >= innerRadius * innerRadius && squaredLength < outerRadius * outerRadius) { + return it + } + } + } +} + +fun Vector3.Companion.uniform(min: Double = -1.0, max: Double = 1.0): Vector3 = + Vector3.uniform(Vector3(min, min, min), Vector3(max, max, max)) + +fun Vector3.Companion.uniform(min: Vector3 = -ONE, max: Vector3 = ONE): Vector3 { + return Vector3(Double.uniform(min.x, max.x), Double.uniform(min.y, max.y), Double.uniform(min.z, max.z)) +} + +// squared length 'polyfill' for OPENRNDR 0.3.30 +private val Vector3.squaredLength__: Double get() = x * x + y * y + z * z + +fun Vector3.Companion.uniformRing(innerRadius: Double = 0.0, outerRadius: Double = 1.0): Vector3 { + while (true) { + uniform(-outerRadius, outerRadius).let { + val squaredLength = it.squaredLength__ + if (squaredLength >= innerRadius * innerRadius && squaredLength < outerRadius * outerRadius) { + return it + } + } + } +} + +// squared length 'polyfill' for OPENRNDR 0.3.30 +private val Vector4.squaredLength__: Double get() = x * x + y * y + z * z + w * w + +fun Vector4.Companion.uniform(min: Double = -1.0, max: Double = 1.0): Vector4 = + Vector4.uniform(Vector4(min, min, min, min), Vector4(max, max,max, max)) + +fun Vector4.Companion.uniform(min: Vector4 = -ONE, max: Vector4 = ONE): Vector4 { + return Vector4(Double.uniform(min.x, max.x), Double.uniform(min.y, max.y), Double.uniform(min.z, max.z), Double.uniform(min.w, max.w)) +} + +fun Vector4.Companion.uniformRing(innerRadius: Double = 0.0, outerRadius: Double = 1.0): Vector4 { + while (true) { + uniform(-outerRadius, outerRadius).let { + val squaredLength = it.squaredLength__ + if (squaredLength >= innerRadius * innerRadius && squaredLength < outerRadius * outerRadius) { + return it + } + } + } +} + diff --git a/orx-noise/src/main/kotlin/ValueNoise2D.kt b/orx-noise/src/main/kotlin/ValueNoise2D.kt index 6070d6317..222000efc 100644 --- a/orx-noise/src/main/kotlin/ValueNoise2D.kt +++ b/orx-noise/src/main/kotlin/ValueNoise2D.kt @@ -1,21 +1,21 @@ -package org.openrndr.extra.noise - -fun valueLinear(seed: Int, x:Double, y:Double) = value(seed, x, y, ::linear) -fun valueQuintic(seed: Int, x:Double, y:Double) = value(seed, x, y, ::quintic) -fun valueHermite(seed: Int, x:Double, y:Double) = value(seed, x, y, ::hermite) - - -inline fun value(seed: Int, x: Double, y: Double, crossinline interpolation: (Double) -> Double = ::linear): Double { - val x0 = x.fastFloor() - val y0 = y.fastFloor() - val x1 = x0 + 1 - val y1 = y0 + 1 - - val xs = interpolation(x - x0) - val ys = interpolation(y - y0) - - val xf0 = lerp(valCoord2D(seed, x0, y0), valCoord2D(seed, x1, y0), xs) - val xf1 = lerp(valCoord2D(seed, x0, y1), valCoord2D(seed, x1, y1), xs) - - return lerp(xf0, xf1, ys) +package org.openrndr.extra.noise + +fun valueLinear(seed: Int, x:Double, y:Double) = value(seed, x, y, ::linear) +fun valueQuintic(seed: Int, x:Double, y:Double) = value(seed, x, y, ::quintic) +fun valueHermite(seed: Int, x:Double, y:Double) = value(seed, x, y, ::hermite) + + +inline fun value(seed: Int, x: Double, y: Double, crossinline interpolation: (Double) -> Double = ::linear): Double { + val x0 = x.fastFloor() + val y0 = y.fastFloor() + val x1 = x0 + 1 + val y1 = y0 + 1 + + val xs = interpolation(x - x0) + val ys = interpolation(y - y0) + + val xf0 = lerp(valCoord2D(seed, x0, y0), valCoord2D(seed, x1, y0), xs) + val xf1 = lerp(valCoord2D(seed, x0, y1), valCoord2D(seed, x1, y1), xs) + + return lerp(xf0, xf1, ys) } \ No newline at end of file diff --git a/orx-noise/src/main/kotlin/ValueNoise3D.kt b/orx-noise/src/main/kotlin/ValueNoise3D.kt index 642d021d9..790fd1285 100644 --- a/orx-noise/src/main/kotlin/ValueNoise3D.kt +++ b/orx-noise/src/main/kotlin/ValueNoise3D.kt @@ -1,29 +1,29 @@ -package org.openrndr.extra.noise - -fun valueLinear(seed: Int, x:Double, y:Double, z:Double) = value(seed, x, y, z, ::linear) -fun valueQuintic(seed: Int, x:Double, y:Double, z:Double) = value(seed, x, y, z, ::quintic) -fun valueHermite(seed: Int, x:Double, y:Double, z:Double) = value(seed, x, y, z, ::hermite) - -inline fun value(seed:Int, x: Double, y: Double, z: Double, crossinline interpolation:(Double)->Double = ::linear) : Double { - val x0 = x.fastFloor() - val y0 = y.fastFloor() - val z0 = z.fastFloor() - val x1 = x0 + 1 - val y1 = y0 + 1 - val z1 = z0 + 1 - - val xs = interpolation(x - x0) - val ys = interpolation(y - y0) - val zs = interpolation(z - z0) - - - val xf00 = lerp(valCoord3D(seed, x0, y0, z0), valCoord3D(seed, x1, y0, z0), xs) - val xf10 = lerp(valCoord3D(seed, x0, y1, z0), valCoord3D(seed, x1, y1, z0), xs) - val xf01 = lerp(valCoord3D(seed, x0, y0, z1), valCoord3D(seed, x1, y0, z1), xs) - val xf11 = lerp(valCoord3D(seed, x0, y1, z1), valCoord3D(seed, x1, y1, z1), xs) - - val yf0 = lerp(xf00, xf10, ys) - val yf1 = lerp(xf01, xf11, ys) - - return lerp(yf0, yf1, zs) +package org.openrndr.extra.noise + +fun valueLinear(seed: Int, x:Double, y:Double, z:Double) = value(seed, x, y, z, ::linear) +fun valueQuintic(seed: Int, x:Double, y:Double, z:Double) = value(seed, x, y, z, ::quintic) +fun valueHermite(seed: Int, x:Double, y:Double, z:Double) = value(seed, x, y, z, ::hermite) + +inline fun value(seed:Int, x: Double, y: Double, z: Double, crossinline interpolation:(Double)->Double = ::linear) : Double { + val x0 = x.fastFloor() + val y0 = y.fastFloor() + val z0 = z.fastFloor() + val x1 = x0 + 1 + val y1 = y0 + 1 + val z1 = z0 + 1 + + val xs = interpolation(x - x0) + val ys = interpolation(y - y0) + val zs = interpolation(z - z0) + + + val xf00 = lerp(valCoord3D(seed, x0, y0, z0), valCoord3D(seed, x1, y0, z0), xs) + val xf10 = lerp(valCoord3D(seed, x0, y1, z0), valCoord3D(seed, x1, y1, z0), xs) + val xf01 = lerp(valCoord3D(seed, x0, y0, z1), valCoord3D(seed, x1, y0, z1), xs) + val xf11 = lerp(valCoord3D(seed, x0, y1, z1), valCoord3D(seed, x1, y1, z1), xs) + + val yf0 = lerp(xf00, xf10, ys) + val yf1 = lerp(xf01, xf11, ys) + + return lerp(yf0, yf1, zs) } \ No newline at end of file