Skip to content

Commit db0917c

Browse files
committed
Introduce noise delegate pattern
1 parent 9b766fa commit db0917c

File tree

11 files changed

+13801
-13516
lines changed

11 files changed

+13801
-13516
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
**v3.8.0** Refactor noise to delegate pattern, improve default implementation and add simplex noise option
2+
13
**v3.7.1** Recommend JRuby-9.2.15.0 use
24

35
**v3.5.0** Rebase processing core code around Sam Pottingers latest fixes for JOGL an image save, does mean breaking some of Diwis and Joshua Davis examples, but one hopes codeanticode knows what he's doing.

lib/propane/version.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# frozen_string_literal: true
22

33
module Propane
4-
VERSION = '3.7.1'
4+
VERSION = '3.8.0'
55
end

pom.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
project 'propane', 'https://github.com/monkstone/propane' do
44
model_version '4.0.0'
5-
id 'propane:propane:3.7.1'
5+
id 'propane:propane:3.8.0'
66
packaging 'jar'
77

88
description 'An integrated processing-core (somewhat hacked), with additional java code for a jruby version of processing.'
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
/*
2+
* Copyright (c) 2021 Martin Prout
3+
*
4+
* This library is free software; you can redistribute it and/or
5+
* modify it under the terms of the GNU Lesser General Public
6+
* License as published by the Free Software Foundation; either
7+
* version 2.1 of the License, or (at your option) any later version.
8+
*
9+
* http://creativecommons.org/licenses/LGPL/2.1/
10+
*
11+
* This library is distributed in the hope that it will be useful,
12+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14+
* Lesser General Public License for more details.
15+
*
16+
* You should have received a copy of the GNU Lesser General Public
17+
* License along with this library; if not, write to the Free Software
18+
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19+
*/
20+
package monkstone.fastmath;
21+
22+
public final class DegLutTables {
23+
24+
/**
25+
*
26+
*/
27+
static public final float PI = 3.1415927f;
28+
29+
/**
30+
*
31+
*/
32+
static public final float PI2 = PI * 2;
33+
static private final int SIN_BITS = 15; // 16KB. Adjust for accuracy.
34+
static private final int SIN_MASK = ~(-1 << SIN_BITS);
35+
static private final int SIN_COUNT = SIN_MASK + 1;
36+
37+
static private final float RAD_FULL = PI * 2;
38+
static private final float DEG_FULL = 360;
39+
static private final float RAD_TO_INDEX = SIN_COUNT / RAD_FULL;
40+
static private final float DEG_TO_INDEX = SIN_COUNT / DEG_FULL;
41+
42+
/**
43+
* multiply by this to convert from radians to degrees
44+
*/
45+
static public final float RADIANS_TO_DEGREES = 180f / PI;
46+
47+
/**
48+
*
49+
*/
50+
static public final float RAD_DEG = RADIANS_TO_DEGREES;
51+
/**
52+
* multiply by this to convert from degrees to radians
53+
*/
54+
static public final float DEGREES_TO_RADIANS = PI / 180;
55+
56+
/**
57+
*
58+
*/
59+
static public final float DEG_RAD = DEGREES_TO_RADIANS;
60+
61+
static private class Sin {
62+
63+
static final float[] table = new float[SIN_COUNT];
64+
65+
static {
66+
for (int i = 0; i < SIN_COUNT; i++) {
67+
table[i] = (float) Math.sin((i + 0.5f) / SIN_COUNT * RAD_FULL);
68+
}
69+
for (int i = 0; i < 360; i += 90) {
70+
table[(int) (i * DEG_TO_INDEX) & SIN_MASK] = (float) Math.sin(i * DEGREES_TO_RADIANS);
71+
}
72+
}
73+
}
74+
75+
/**
76+
* Returns the sine in radians from a lookup table.
77+
* @param radians
78+
* @return
79+
*/
80+
static public final float sin(float radians) {
81+
return Sin.table[(int) (radians * RAD_TO_INDEX) & SIN_MASK];
82+
}
83+
84+
/**
85+
* Returns the cosine in radians from a lookup table.
86+
* @param radians
87+
* @return
88+
*/
89+
static public final float cos(float radians) {
90+
return Sin.table[(int) ((radians + PI / 2) * RAD_TO_INDEX) & SIN_MASK];
91+
}
92+
93+
/**
94+
* Returns the sine in radians from a lookup table.
95+
* @param degrees
96+
* @return
97+
*/
98+
static public final float sinDeg(float degrees) {
99+
return Sin.table[(int) (degrees * DEG_TO_INDEX) & SIN_MASK];
100+
}
101+
102+
/**
103+
* Returns the cosine in radians from a lookup table.
104+
* @param degrees
105+
* @return
106+
*/
107+
static public final float cosDeg(float degrees) {
108+
return Sin.table[(int) ((degrees + 90) * DEG_TO_INDEX) & SIN_MASK];
109+
}
110+
}
111+
Lines changed: 6 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2015-20 Martin Prout
2+
* Copyright (c) 2015-21 Martin Prout
33
*
44
* This library is free software; you can redistribute it and/or
55
* modify it under the terms of the GNU Lesser General Public
@@ -20,7 +20,7 @@
2020
package monkstone.fastmath;
2121

2222
import org.jruby.Ruby;
23-
import org.jruby.RubyInteger;
23+
import org.jruby.RubyNumeric;
2424
import org.jruby.RubyModule;
2525
import org.jruby.anno.JRubyModule;
2626
import org.jruby.anno.JRubyMethod;
@@ -34,46 +34,13 @@
3434
@JRubyModule(name = "DegLut")
3535
public class Deglut {
3636

37-
/**
38-
* Lookup table for degree cosine/sine, has a fixed precision 1.0 degrees
39-
* Quite accurate but imprecise
40-
*
41-
* @author Martin Prout <[email protected]>
42-
*/
43-
static final double[] SIN_DEG_LUT = new double[91];
44-
/**
45-
*
46-
*/
47-
public static final double TO_RADIANS = Math.PI / 180;
48-
/**
49-
*
50-
*/
51-
private static boolean initialized = false;
52-
53-
private final static int NINETY = 90;
54-
private final static int FULL = 360;
55-
private static final long serialVersionUID = -1466528933765940101L;
56-
57-
/**
58-
* Initialize sin table with values (first quadrant only)
59-
*/
60-
public static final void initTable() {
61-
if (initialized == false) {
62-
for (int i = 0; i <= NINETY; i++) {
63-
SIN_DEG_LUT[i] = Math.sin(TO_RADIANS * i);
64-
}
65-
initialized = true;
66-
}
67-
}
68-
6937
/**
7038
*
7139
* @param runtime Ruby
7240
*/
7341
public static void createDeglut(final Ruby runtime) {
7442
RubyModule deglutModule = runtime.defineModule("DegLut");
7543
deglutModule.defineAnnotatedMethods(Deglut.class);
76-
Deglut.initTable();
7744
}
7845

7946
/**
@@ -84,18 +51,9 @@ public static void createDeglut(final Ruby runtime) {
8451
* @return sin IRubyObject
8552
*/
8653
@JRubyMethod(name = "sin", module = true)
87-
8854
public static IRubyObject sin(ThreadContext context, IRubyObject recv, IRubyObject other) {
89-
int thet = (int) ((RubyInteger) other).getLongValue();
90-
while (thet < 0) {
91-
thet += FULL; // Needed because negative modulus plays badly in java
92-
}
93-
int theta = thet % FULL;
94-
int y = theta % NINETY;
95-
double result = (theta < NINETY) ? SIN_DEG_LUT[y] : (theta < 180)
96-
? SIN_DEG_LUT[NINETY - y] : (theta < 270)
97-
? -SIN_DEG_LUT[y] : -SIN_DEG_LUT[NINETY - y];
98-
return context.runtime.newFloat(result);
55+
float thet = (float) ((RubyNumeric) other).getLongValue();
56+
return context.runtime.newFloat(DegLutTables.sinDeg(thet));
9957
}
10058

10159
/**
@@ -107,15 +65,7 @@ public static IRubyObject sin(ThreadContext context, IRubyObject recv, IRubyObje
10765
*/
10866
@JRubyMethod(name = "cos", module = true)
10967
public static IRubyObject cos(ThreadContext context, IRubyObject recv, IRubyObject other) {
110-
int thet = (int) ((RubyInteger) other).getLongValue();
111-
while (thet < 0) {
112-
thet += FULL; // Needed because negative modulus plays badly in java
113-
}
114-
int theta = thet % FULL;
115-
int y = theta % NINETY;
116-
double result = (theta < NINETY) ? SIN_DEG_LUT[NINETY - y] : (theta < 180)
117-
? -SIN_DEG_LUT[y] : (theta < 270)
118-
? -SIN_DEG_LUT[NINETY - y] : SIN_DEG_LUT[y];
119-
return context.runtime.newFloat(result);
68+
float thet = (float) ((RubyNumeric) other).getLongValue();
69+
return context.runtime.newFloat(DegLutTables.cosDeg(thet));
12070
}
12171
}
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
package monkstone.noise;
2+
3+
/*
4+
* Copyright (c) 2021 Martin Prout
5+
*
6+
* This library is free software; you can redistribute it and/or
7+
* modify it under the terms of the GNU General Public
8+
* License as published by the Free Software Foundation; either
9+
* version 3.0 of the License, or (at your option) any later version.
10+
*
11+
* http://creativecommons.org/licenses/LGPL/2.1/
12+
*
13+
* This library is distributed in the hope that it will be useful,
14+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
15+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16+
* Lesser General Public License for more details.
17+
*
18+
* You should have received a copy of the GNU General Public
19+
* License along with this library; if not, write to the Free Software
20+
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21+
*/
22+
public interface Noise {
23+
24+
/**
25+
*
26+
* @param x
27+
* @return
28+
*/
29+
default float noise(float x) {
30+
return noise(x, 0);
31+
}
32+
33+
/**
34+
*
35+
* @param x
36+
* @param y
37+
* @return
38+
*/
39+
default float noise(float x, float y) {
40+
return noise(x, y, 0);
41+
}
42+
43+
/**
44+
* <p>
45+
* Returns the Perlin noise value at specified coordinates. Perlin noise is
46+
* a random sequence generator producing a more natural ordered, harmonic
47+
* succession of numbers compared to the standard <b>random()</b> function.
48+
* It was invented by Ken Perlin in the 1980s and been used since in
49+
* graphical applications to produce procedural textures, natural motion,
50+
* shapes, terrains etc. The main difference to the
51+
* <b>random()</b> function is that Perlin noise is defined in an infinite
52+
* n-dimensional space where each pair of coordinates corresponds to a fixed
53+
* semi-random value (fixed only for the lifespan of the program). The
54+
* resulting value will always be between 0.0 and 1.0. Processing can
55+
* compute 1D, 2D and 3D noise, depending on the number of coordinates
56+
* given. The noise value can be animated by moving through the noise space
57+
* as demonstrated in the example above. The 2nd and 3rd dimension can also
58+
* be interpreted as time.The actual noise is structured similar to an audio
59+
* signal, in respect to the function's use of frequencies. Similar to the
60+
* concept of harmonics in physics, perlin noise is computed over several
61+
* octaves which are added together for the final result. Another way to
62+
* adjust the character of the resulting sequence is the scale of the input
63+
* coordinates. As the function works within an infinite space the value of
64+
* the coordinates doesn't matter as such, only the distance between
65+
* successive coordinates does (eg. when using <b>noise()</b> within a
66+
* loop). As a general rule the smaller the difference between coordinates,
67+
* the smoother the resulting noise sequence will be. Steps of 0.005-0.03
68+
* work best for most applications, but this will differ depending on use.
69+
* <p>
70+
* @param x x-coordinate in noise space
71+
* @param y y-coordinate in noise space
72+
* @param z z-coordinate in noise space
73+
* @return
74+
*/
75+
float noise(float x, float y, float z);
76+
77+
/**
78+
* Adjusts the character and level of detail produced by the Perlin noise
79+
* function.Similar to harmonics in physics, noise is computed over several
80+
* octaves. Lower octaves contribute more to the output signal and as such
81+
* define the overal intensity of the noise, whereas higher octaves create
82+
* finer grained details in the noise sequence. By default, noise is
83+
* computed over 4 octaves with each octave contributing exactly half than
84+
* its predecessor, starting at 50% strength for the 1st octave. This
85+
* falloff amount can be changed by adding an additional function parameter.
86+
* Eg. a falloff factor of 0.75 means each octave will now have 75% impact
87+
* (25% less) of the previous lower octave. Any value between 0.0 and 1.0 is
88+
* valid, however note that values greater than 0.5 might result in greater
89+
* than 1.0 values returned by <b>noise()</b>.By changing these parameters,
90+
* the signal created by the <b>noise()</b>
91+
* function can be adapted to fit very specific needs and characteristics.
92+
*
93+
* @param lod
94+
*/
95+
void noiseDetail(int lod);
96+
97+
/**
98+
* @param lod
99+
* @param falloff falloff factor for each octave
100+
*/
101+
void noiseDetail(int lod, float falloff);
102+
103+
/**
104+
* Sets the seed value for <b>noise()</b>.By default, <b>noise()</b>
105+
* produces different results each time the program is run. Set the
106+
* <b>value</b> parameter to a constant to return the same pseudo-random
107+
* numbers each time the software is run.
108+
*
109+
* @param seed
110+
*/
111+
void noiseSeed(long seed);
112+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/*
2+
* To change this license header, choose License Headers in Project Properties.
3+
* To change this template file, choose Tools | Templates
4+
* and open the template in the editor.
5+
*/
6+
package monkstone.noise;
7+
8+
/**
9+
*
10+
* @author Martin Prout
11+
*/
12+
public class NoiseGenerator implements Noise{
13+
14+
private final Noise implementation;
15+
16+
public NoiseGenerator(){
17+
this.implementation = new ValueNoise();
18+
19+
}
20+
21+
public NoiseGenerator(Noise implementation){
22+
this.implementation = implementation;
23+
}
24+
25+
@Override
26+
public float noise(float x, float y, float z) {
27+
return implementation.noise(x, y, z);
28+
}
29+
30+
@Override
31+
public void noiseDetail(int lod) {
32+
implementation.noiseDetail(lod);
33+
}
34+
35+
@Override
36+
public void noiseDetail(int lod, float falloff) {
37+
implementation.noiseDetail(lod, falloff);
38+
}
39+
40+
@Override
41+
public void noiseSeed(long seed) {
42+
implementation.noiseSeed(seed);
43+
}
44+
45+
}

0 commit comments

Comments
 (0)