diff options
author | olamedia <[email protected]> | 2012-09-28 18:46:42 +0600 |
---|---|---|
committer | olamedia <[email protected]> | 2012-09-28 18:46:42 +0600 |
commit | b4192c7a88bad111bebbd42d391d6e729c8617d6 (patch) | |
tree | b05a586dbc60c5427fcc7f3fe01cf2fdcb970272 /src |
initial
Diffstat (limited to 'src')
233 files changed, 18371 insertions, 0 deletions
diff --git a/src/libnoiseforjava/Interp.java b/src/libnoiseforjava/Interp.java new file mode 100644 index 0000000..53ed56d --- /dev/null +++ b/src/libnoiseforjava/Interp.java @@ -0,0 +1,107 @@ +/*
+ * Copyright (C) 2003, 2004 Jason Bevins (original libnoise code)
+ * Copyright 2010 Thomas J. Hodge (java port of libnoise)
+ *
+ * This file is part of libnoiseforjava.
+ *
+ * libnoiseforjava is a Java port of the C++ library libnoise, which may be found at
+ * http://libnoise.sourceforge.net/. libnoise was developed by Jason Bevins, who may be
+ * contacted at [email protected] (for great email, take off every 'zig').
+ * Porting to Java was done by Thomas Hodge, who may be contacted at
+ * [email protected] (remove every 'zag').
+ *
+ * libnoiseforjava is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * libnoiseforjava is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * libnoiseforjava. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package libnoiseforjava;
+
+public class Interp
+{
+
+ /// Performs cubic interpolation between two values bound between two other
+ /// values.
+ ///
+ /// @param n0 The value before the first value.
+ /// @param n1 The first value.
+ /// @param n2 The second value.
+ /// @param n3 The value after the second value.
+ /// @param a The alpha value.
+ ///
+ /// @returns The interpolated value.
+ ///
+ /// The alpha value should range from 0.0 to 1.0. If the alpha value is
+ /// 0.0, this function returns @a n1. If the alpha value is 1.0, this
+ /// function returns @a n2.
+ public static double cubicInterp (double n0, double n1, double n2, double n3,
+ double a)
+ {
+ double p = (n3 - n2) - (n0 - n1);
+ double q = (n0 - n1) - p;
+ double r = n2 - n0;
+ double s = n1;
+ return p * a * a * a + q * a * a + r * a + s;
+ }
+
+ /// Performs linear interpolation between two values.
+ ///
+ /// @param n0 The first value.
+ /// @param n1 The second value.
+ /// @param a The alpha value.
+ ///
+ /// @returns The interpolated value.
+ ///
+ /// The alpha value should range from 0.0 to 1.0. If the alpha value is
+ /// 0.0, this function returns @a n0. If the alpha value is 1.0, this
+ /// function returns @a n1.
+ public static double linearInterp (double n0, double n1, double a)
+ {
+ return ((1.0 - a) * n0) + (a * n1);
+ }
+
+ /// Maps a value onto a cubic S-curve.
+ ///
+ /// @param a The value to map onto a cubic S-curve.
+ ///
+ /// @returns The mapped value.
+ ///
+ /// @a a should range from 0.0 to 1.0.
+ ///
+ /// The derivative of a cubic S-curve is zero at @a a = 0.0 and @a a =
+ /// 1.0
+ public static double SCurve3 (double a)
+ {
+ return (a * a * (3.0 - 2.0 * a));
+ }
+
+ /// Maps a value onto a quintic S-curve.
+ ///
+ /// @param a The value to map onto a quintic S-curve.
+ ///
+ /// @returns The mapped value.
+ ///
+ /// @a a should range from 0.0 to 1.0.
+ ///
+ /// The first derivative of a quintic S-curve is zero at @a a = 0.0 and
+ /// @a a = 1.0
+ ///
+ /// The second derivative of a quintic S-curve is zero at @a a = 0.0 and
+ /// @a a = 1.0
+ static double SCurve5 (double a)
+ {
+ double a3 = a * a * a;
+ double a4 = a3 * a;
+ double a5 = a4 * a;
+ return (6.0 * a5) - (15.0 * a4) + (10.0 * a3);
+ }
+
+}
diff --git a/src/libnoiseforjava/Misc.java b/src/libnoiseforjava/Misc.java new file mode 100644 index 0000000..11d2a7f --- /dev/null +++ b/src/libnoiseforjava/Misc.java @@ -0,0 +1,51 @@ +/*
+ * Copyright (C) 2003, 2004 Jason Bevins (original libnoise code)
+ * Copyright 2010 Thomas J. Hodge (java port of libnoise)
+ *
+ * This file is part of libnoiseforjava.
+ *
+ * libnoiseforjava is a Java port of the C++ library libnoise, which may be found at
+ * http://libnoise.sourceforge.net/. libnoise was developed by Jason Bevins, who may be
+ * contacted at [email protected] (for great email, take off every 'zig').
+ * Porting to Java was done by Thomas Hodge, who may be contacted at
+ * [email protected] (remove every 'zag').
+ *
+ * libnoiseforjava is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * libnoiseforjava is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * libnoiseforjava. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package libnoiseforjava;
+
+public class Misc
+{
+ /// Clamps a value onto a clamping range.
+ ///
+ /// @param value The value to clamp.
+ /// @param lowerBound The lower bound of the clamping range.
+ /// @param upperBound The upper bound of the clamping range.
+ ///
+ /// @returns
+ /// - @a value if @a value lies between @a lowerBound and @a upperBound.
+ /// - @a lowerBound if @a value is less than @a lowerBound.
+ /// - @a upperBound if @a value is greater than @a upperBound.
+ ///
+ /// This function does not modify any parameters.
+ public static int ClampValue (int value, int lowerBound, int upperBound)
+ {
+ if (value < lowerBound)
+ return lowerBound;
+ else if (value > upperBound)
+ return upperBound;
+ else
+ return value;
+ }
+}
diff --git a/src/libnoiseforjava/NoiseGen.java b/src/libnoiseforjava/NoiseGen.java new file mode 100644 index 0000000..fd98be3 --- /dev/null +++ b/src/libnoiseforjava/NoiseGen.java @@ -0,0 +1,261 @@ +/*
+ * Copyright (C) 2003, 2004 Jason Bevins (original libnoise code)
+ * Copyright 2010 Thomas J. Hodge (java port of libnoise)
+ *
+ * This file is part of libnoiseforjava.
+ *
+ * libnoiseforjava is a Java port of the C++ library libnoise, which may be found at
+ * http://libnoise.sourceforge.net/. libnoise was developed by Jason Bevins, who may be
+ * contacted at [email protected] (for great email, take off every 'zig').
+ * Porting to Java was done by Thomas Hodge, who may be contacted at
+ * [email protected] (remove every 'zag').
+ *
+ * libnoiseforjava is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * libnoiseforjava is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * libnoiseforjava. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package libnoiseforjava;
+
+public class NoiseGen
+{
+
+ /// Enumerates the noise quality.
+ public enum NoiseQuality
+ {
+
+ /// Generates coherent noise quickly. When a coherent-noise function with
+ /// this quality setting is used to generate a bump-map image, there are
+ /// noticeable "creasing" artifacts in the resulting image. This is
+ /// because the derivative of that function is discontinuous at integer
+ /// boundaries.
+ QUALITY_FAST,
+
+ /// Generates standard-quality coherent noise. When a coherent-noise
+ /// function with this quality setting is used to generate a bump-map
+ /// image, there are some minor "creasing" artifacts in the resulting
+ /// image. This is because the second derivative of that function is
+ /// discontinuous at integer boundaries.
+ QUALITY_STD,
+
+ /// Generates the best-quality coherent noise. When a coherent-noise
+ /// function with this quality setting is used to generate a bump-map
+ /// image, there are no "creasing" artifacts in the resulting image. This
+ /// is because the first and second derivatives of that function are
+ /// continuous at integer boundaries.
+ QUALITY_BEST
+ }
+
+ static final int X_NOISE_GEN = 1619;
+ static final int Y_NOISE_GEN = 31337;
+ static final int Z_NOISE_GEN = 6971;
+ static final int SEED_NOISE_GEN = 1013;
+ static final int SHIFT_NOISE_GEN = 8;
+
+ public static double GradientCoherentNoise3D (double x, double y, double z, int seed,
+ NoiseQuality noiseQuality)
+ {
+
+ // Create a unit-length cube aligned along an integer boundary. This cube
+ // surrounds the input point.
+ int x0 = (x > 0.0? (int)x: (int)x - 1);
+ int x1 = x0 + 1;
+ int y0 = (y > 0.0? (int)y: (int)y - 1);
+ int y1 = y0 + 1;
+ int z0 = (z > 0.0? (int)z: (int)z - 1);
+ int z1 = z0 + 1;
+
+ // Map the difference between the coordinates of the input value and the
+ // coordinates of the cube's outer-lower-left vertex onto an S-curve.
+ double xs = 0, ys = 0, zs = 0;
+ switch (noiseQuality)
+ {
+ case QUALITY_FAST:
+ xs = (x - (double)x0);
+ ys = (y - (double)y0);
+ zs = (z - (double)z0);
+ break;
+ case QUALITY_STD:
+ xs = Interp.SCurve3 (x - (double)x0);
+ ys = Interp.SCurve3 (y - (double)y0);
+ zs = Interp.SCurve3 (z - (double)z0);
+ break;
+ case QUALITY_BEST:
+ xs = Interp.SCurve5 (x - (double)x0);
+ ys = Interp.SCurve5 (y - (double)y0);
+ zs = Interp.SCurve5 (z - (double)z0);
+ break;
+ }
+
+ // Now calculate the noise values at each vertex of the cube. To generate
+ // the coherent-noise value at the input point, interpolate these eight
+ // noise values using the S-curve value as the interpolant (trilinear
+ // interpolation.)
+ double n0, n1, ix0, ix1, iy0, iy1;
+ n0 = GradientNoise3D (x, y, z, x0, y0, z0, seed);
+ n1 = GradientNoise3D (x, y, z, x1, y0, z0, seed);
+ ix0 = Interp.linearInterp (n0, n1, xs);
+ n0 = GradientNoise3D (x, y, z, x0, y1, z0, seed);
+ n1 = GradientNoise3D (x, y, z, x1, y1, z0, seed);
+ ix1 = Interp.linearInterp (n0, n1, xs);
+ iy0 = Interp.linearInterp (ix0, ix1, ys);
+ n0 = GradientNoise3D (x, y, z, x0, y0, z1, seed);
+ n1 = GradientNoise3D (x, y, z, x1, y0, z1, seed);
+ ix0 = Interp.linearInterp (n0, n1, xs);
+ n0 = GradientNoise3D (x, y, z, x0, y1, z1, seed);
+ n1 = GradientNoise3D (x, y, z, x1, y1, z1, seed);
+ ix1 = Interp.linearInterp (n0, n1, xs);
+ iy1 = Interp.linearInterp (ix0, ix1, ys);
+
+ return Interp.linearInterp (iy0, iy1, zs);
+ }
+
+ public static double GradientNoise3D (double fx, double fy, double fz, int ix,
+ int iy, int iz, int seed)
+ {
+
+ //VectorTable vectorTable = new VectorTable();
+ // Randomly generate a gradient vector given the integer coordinates of the
+ // input value. This implementation generates a random number and uses it
+ // as an index into a normalized-vector lookup table.
+ int vectorIndex = (X_NOISE_GEN * ix
+ + Y_NOISE_GEN * iy
+ + Z_NOISE_GEN * iz
+ + SEED_NOISE_GEN * seed)
+ & 0xffffffff;
+
+ vectorIndex ^= (vectorIndex >> SHIFT_NOISE_GEN);
+ vectorIndex &= 0xff;
+
+ double xvGradient = VectorTable.getRandomVectors(vectorIndex, 0);
+ double yvGradient = VectorTable.getRandomVectors(vectorIndex, 1);
+ double zvGradient = VectorTable.getRandomVectors(vectorIndex, 2);
+ // array size too large when using this original, changed to above for all 3
+ // double zvGradient = vectorTable.getRandomVectors(vectorIndex << 2, 2);
+
+ // Set up us another vector equal to the distance between the two vectors
+ // passed to this function.
+ double xvPoint = (fx - (double)ix);
+ double yvPoint = (fy - (double)iy);
+ double zvPoint = (fz - (double)iz);
+
+ // Now compute the dot product of the gradient vector with the distance
+ // vector. The resulting value is gradient noise. Apply a scaling value
+ // so that this noise value ranges from -1.0 to 1.0.
+ return ((xvGradient * xvPoint)
+ + (yvGradient * yvPoint)
+ + (zvGradient * zvPoint)) * 2.12;
+ }
+
+ public static int IntValueNoise3D (int x, int y, int z, int seed)
+ {
+ // All constants are primes and must remain prime in order for this noise
+ // function to work correctly.
+ int n = (X_NOISE_GEN * x
+ + Y_NOISE_GEN * y
+ + Z_NOISE_GEN * z
+ + SEED_NOISE_GEN * seed)
+ & 0x7fffffff;
+
+ n = (n >> 13) ^ n;
+
+ return (n * (n * n * 60493 + 19990303) + 1376312589) & 0x7fffffff;
+ }
+
+ public static double ValueCoherentNoise3D (double x, double y, double z, int seed,
+ NoiseQuality noiseQuality)
+ {
+ // Create a unit-length cube aligned along an integer boundary. This cube
+ // surrounds the input point.
+ int x0 = (x > 0.0? (int)x: (int)x - 1);
+ int x1 = x0 + 1;
+ int y0 = (y > 0.0? (int)y: (int)y - 1);
+ int y1 = y0 + 1;
+ int z0 = (z > 0.0? (int)z: (int)z - 1);
+ int z1 = z0 + 1;
+
+ // Map the difference between the coordinates of the input value and the
+ // coordinates of the cube's outer-lower-left vertex onto an S-curve.
+ double xs = 0, ys = 0, zs = 0;
+ switch (noiseQuality)
+ {
+ case QUALITY_FAST:
+ xs = (x - (double)x0);
+ ys = (y - (double)y0);
+ zs = (z - (double)z0);
+ break;
+ case QUALITY_STD:
+ xs = Interp.SCurve3 (x - (double)x0);
+ ys = Interp.SCurve3 (y - (double)y0);
+ zs = Interp.SCurve3 (z - (double)z0);
+ break;
+ case QUALITY_BEST:
+ xs = Interp.SCurve5 (x - (double)x0);
+ ys = Interp.SCurve5 (y - (double)y0);
+ zs = Interp.SCurve5 (z - (double)z0);
+ break;
+ }
+
+ // Now calculate the noise values at each vertex of the cube. To generate
+ // the coherent-noise value at the input point, interpolate these eight
+ // noise values using the S-curve value as the interpolant (trilinear
+ // interpolation.)
+ double n0, n1, ix0, ix1, iy0, iy1;
+ n0 = ValueNoise3D (x0, y0, z0, seed);
+ n1 = ValueNoise3D (x1, y0, z0, seed);
+ ix0 = Interp.linearInterp (n0, n1, xs);
+ n0 = ValueNoise3D (x0, y1, z0, seed);
+ n1 = ValueNoise3D (x1, y1, z0, seed);
+ ix1 = Interp.linearInterp (n0, n1, xs);
+ iy0 = Interp.linearInterp (ix0, ix1, ys);
+ n0 = ValueNoise3D (x0, y0, z1, seed);
+ n1 = ValueNoise3D (x1, y0, z1, seed);
+ ix0 = Interp.linearInterp (n0, n1, xs);
+ n0 = ValueNoise3D (x0, y1, z1, seed);
+ n1 = ValueNoise3D (x1, y1, z1, seed);
+ ix1 = Interp.linearInterp (n0, n1, xs);
+ iy1 = Interp.linearInterp (ix0, ix1, ys);
+
+ return Interp.linearInterp (iy0, iy1, zs);
+ }
+
+ public static double ValueNoise3D (int x, int y, int z, int seed)
+ {
+ return 1.0 - ((double)IntValueNoise3D (x, y, z, seed) / 1073741824.0);
+ }
+
+ /// Modifies a floating-point value so that it can be stored in a
+ /// int32 variable.
+ ///
+ /// @param n A floating-point number.
+ ///
+ /// @returns The modified floating-point number.
+ ///
+ /// This function does not modify @a n.
+ ///
+ /// In libnoise, the noise-generating algorithms are all integer-based;
+ /// they use variables of type int32. Before calling a noise
+ /// function, pass the @a x, @a y, and @a z coordinates to this function to
+ /// ensure that these coordinates can be cast to a int32 value.
+ ///
+ /// Although you could do a straight cast from double to int32, the
+ /// resulting value may differ between platforms. By using this function,
+ /// you ensure that the resulting value is identical between platforms.
+ public static double MakeInt32Range (double n) {
+ if (n >= 1073741824.0)
+ return (2.0 * (n % 1073741824.0)) - 1073741824.0;
+ else if (n <= -1073741824.0)
+ return (2.0 * (n % 1073741824.0)) + 1073741824.0;
+ else
+ return n;
+ }
+
+}
diff --git a/src/libnoiseforjava/VectorTable.java b/src/libnoiseforjava/VectorTable.java new file mode 100644 index 0000000..7b904a2 --- /dev/null +++ b/src/libnoiseforjava/VectorTable.java @@ -0,0 +1,309 @@ +/*
+ * This file is in the public domain
+ *
+ * This file is part of libnoiseforjava.
+ *
+ * libnoiseforjava is a Java port of the C++ library libnoise, which may be found at
+ * http://libnoise.sourceforge.net/. libnoise was developed by Jason Bevins, who may be
+ * contacted at [email protected] (for great email, take off every 'zig').
+ * Porting to Java was done by Thomas Hodge, who may be contacted at
+ * [email protected] (remove every 'zag').
+ *
+ * libnoiseforjava is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * libnoiseforjava is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * libnoiseforjava. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package libnoiseforjava;
+
+public class VectorTable
+{
+ // A table of 256 random normalized vectors. Each row is an (x, y, z, 0)
+ // coordinate. The 0 is used as padding so we can use bit shifts to index
+ // any row in the table. These vectors have an even statistical
+ // distribution, which improves the quality of the coherent noise
+ // generated by these vectors. For more information, see "GPU Gems",
+ // Chapter 5 - Implementing Improved Perlin Noise by Ken Perlin,
+ // specifically page 76.
+
+ private static double[][] randomVectors = {
+ {-0.763874, -0.596439, -0.246489, 0.0},
+ {0.396055, 0.904518, -0.158073, 0.0},
+ {-0.499004, -0.8665, -0.0131631, 0.0},
+ {0.468724, -0.824756, 0.316346, 0.0},
+ {0.829598, 0.43195, 0.353816, 0.0},
+ {-0.454473, 0.629497, -0.630228, 0.0},
+ {-0.162349, -0.869962, -0.465628, 0.0},
+ {0.932805, 0.253451, 0.256198, 0.0},
+ {-0.345419, 0.927299, -0.144227, 0.0},
+ {-0.715026, -0.293698, -0.634413, 0.0},
+ {-0.245997, 0.717467, -0.651711, 0.0},
+ {-0.967409, -0.250435, -0.037451, 0.0},
+ {0.901729, 0.397108, -0.170852, 0.0},
+ {0.892657, -0.0720622, -0.444938, 0.0},
+ {0.0260084, -0.0361701, 0.999007, 0.0},
+ {0.949107, -0.19486, 0.247439, 0.0},
+ {0.471803, -0.807064, -0.355036, 0.0},
+ {0.879737, 0.141845, 0.453809, 0.0},
+ {0.570747, 0.696415, 0.435033, 0.0},
+ {-0.141751, -0.988233, -0.0574584, 0.0},
+ {-0.58219, -0.0303005, 0.812488, 0.0},
+ {-0.60922, 0.239482, -0.755975, 0.0},
+ {0.299394, -0.197066, -0.933557, 0.0},
+ {-0.851615, -0.220702, -0.47544, 0.0},
+ {0.848886, 0.341829, -0.403169, 0.0},
+ {-0.156129, -0.687241, 0.709453, 0.0},
+ {-0.665651, 0.626724, 0.405124, 0.0},
+ {0.595914, -0.674582, 0.43569, 0.0},
+ {0.171025, -0.509292, 0.843428, 0.0},
+ {0.78605, 0.536414, -0.307222, 0.0},
+ {0.18905, -0.791613, 0.581042, 0.0},
+ {-0.294916, 0.844994, 0.446105, 0.0},
+ {0.342031, -0.58736, -0.7335, 0.0},
+ {0.57155, 0.7869, 0.232635, 0.0},
+ {0.885026, -0.408223, 0.223791, 0.0},
+ {-0.789518, 0.571645, 0.223347, 0.0},
+ {0.774571, 0.31566, 0.548087, 0.0},
+ {-0.79695, -0.0433603, -0.602487, 0.0},
+ {-0.142425, -0.473249, -0.869339, 0.0},
+ {-0.0698838, 0.170442, 0.982886, 0.0},
+ {0.687815, -0.484748, 0.540306, 0.0},
+ {0.543703, -0.534446, -0.647112, 0.0},
+ {0.97186, 0.184391, -0.146588, 0.0},
+ {0.707084, 0.485713, -0.513921, 0.0},
+ {0.942302, 0.331945, 0.043348, 0.0},
+ {0.499084, 0.599922, 0.625307, 0.0},
+ {-0.289203, 0.211107, 0.9337, 0.0},
+ {0.412433, -0.71667, -0.56239, 0.0},
+ {0.87721, -0.082816, 0.47291, 0.0},
+ {-0.420685, -0.214278, 0.881538, 0.0},
+ {0.752558, -0.0391579, 0.657361, 0.0},
+ {0.0765725, -0.996789, 0.0234082, 0.0},
+ {-0.544312, -0.309435, -0.779727, 0.0},
+ {-0.455358, -0.415572, 0.787368, 0.0},
+ {-0.874586, 0.483746, 0.0330131, 0.0},
+ {0.245172, -0.0838623, 0.965846, 0.0},
+ {0.382293, -0.432813, 0.81641, 0.0},
+ {-0.287735, -0.905514, 0.311853, 0.0},
+ {-0.667704, 0.704955, -0.239186, 0.0},
+ {0.717885, -0.464002, -0.518983, 0.0},
+ {0.976342, -0.214895, 0.0240053, 0.0},
+ {-0.0733096, -0.921136, 0.382276, 0.0},
+ {-0.986284, 0.151224, -0.0661379, 0.0},
+ {-0.899319, -0.429671, 0.0812908, 0.0},
+ {0.652102, -0.724625, 0.222893, 0.0},
+ {0.203761, 0.458023, -0.865272, 0.0},
+ {-0.030396, 0.698724, -0.714745, 0.0},
+ {-0.460232, 0.839138, 0.289887, 0.0},
+ {-0.0898602, 0.837894, 0.538386, 0.0},
+ {-0.731595, 0.0793784, 0.677102, 0.0},
+ {-0.447236, -0.788397, 0.422386, 0.0},
+ {0.186481, 0.645855, -0.740335, 0.0},
+ {-0.259006, 0.935463, 0.240467, 0.0},
+ {0.445839, 0.819655, -0.359712, 0.0},
+ {0.349962, 0.755022, -0.554499, 0.0},
+ {-0.997078, -0.0359577, 0.0673977, 0.0},
+ {-0.431163, -0.147516, -0.890133, 0.0},
+ {0.299648, -0.63914, 0.708316, 0.0},
+ {0.397043, 0.566526, -0.722084, 0.0},
+ {-0.502489, 0.438308, -0.745246, 0.0},
+ {0.0687235, 0.354097, 0.93268, 0.0},
+ {-0.0476651, -0.462597, 0.885286, 0.0},
+ {-0.221934, 0.900739, -0.373383, 0.0},
+ {-0.956107, -0.225676, 0.186893, 0.0},
+ {-0.187627, 0.391487, -0.900852, 0.0},
+ {-0.224209, -0.315405, 0.92209, 0.0},
+ {-0.730807, -0.537068, 0.421283, 0.0},
+ {-0.0353135, -0.816748, 0.575913, 0.0},
+ {-0.941391, 0.176991, -0.287153, 0.0},
+ {-0.154174, 0.390458, 0.90762, 0.0},
+ {-0.283847, 0.533842, 0.796519, 0.0},
+ {-0.482737, -0.850448, 0.209052, 0.0},
+ {-0.649175, 0.477748, 0.591886, 0.0},
+ {0.885373, -0.405387, -0.227543, 0.0},
+ {-0.147261, 0.181623, -0.972279, 0.0},
+ {0.0959236, -0.115847, -0.988624, 0.0},
+ {-0.89724, -0.191348, 0.397928, 0.0},
+ {0.903553, -0.428461, -0.00350461, 0.0},
+ {0.849072, -0.295807, -0.437693, 0.0},
+ {0.65551, 0.741754, -0.141804, 0.0},
+ {0.61598, -0.178669, 0.767232, 0.0},
+ {0.0112967, 0.932256, -0.361623, 0.0},
+ {-0.793031, 0.258012, 0.551845, 0.0},
+ {0.421933, 0.454311, 0.784585, 0.0},
+ {-0.319993, 0.0401618, -0.946568, 0.0},
+ {-0.81571, 0.551307, -0.175151, 0.0},
+ {-0.377644, 0.00322313, 0.925945, 0.0},
+ {0.129759, -0.666581, -0.734052, 0.0},
+ {0.601901, -0.654237, -0.457919, 0.0},
+ {-0.927463, -0.0343576, -0.372334, 0.0},
+ {-0.438663, -0.868301, -0.231578, 0.0},
+ {-0.648845, -0.749138, -0.133387, 0.0},
+ {0.507393, -0.588294, 0.629653, 0.0},
+ {0.726958, 0.623665, 0.287358, 0.0},
+ {0.411159, 0.367614, -0.834151, 0.0},
+ {0.806333, 0.585117, -0.0864016, 0.0},
+ {0.263935, -0.880876, 0.392932, 0.0},
+ {0.421546, -0.201336, 0.884174, 0.0},
+ {-0.683198, -0.569557, -0.456996, 0.0},
+ {-0.117116, -0.0406654, -0.992285, 0.0},
+ {-0.643679, -0.109196, -0.757465, 0.0},
+ {-0.561559, -0.62989, 0.536554, 0.0},
+ {0.0628422, 0.104677, -0.992519, 0.0},
+ {0.480759, -0.2867, -0.828658, 0.0},
+ {-0.228559, -0.228965, -0.946222, 0.0},
+ {-0.10194, -0.65706, -0.746914, 0.0},
+ {0.0689193, -0.678236, 0.731605, 0.0},
+ {0.401019, -0.754026, 0.52022, 0.0},
+ {-0.742141, 0.547083, -0.387203, 0.0},
+ {-0.00210603, -0.796417, -0.604745, 0.0},
+ {0.296725, -0.409909, -0.862513, 0.0},
+ {-0.260932, -0.798201, 0.542945, 0.0},
+ {-0.641628, 0.742379, 0.192838, 0.0},
+ {-0.186009, -0.101514, 0.97729, 0.0},
+ {0.106711, -0.962067, 0.251079, 0.0},
+ {-0.743499, 0.30988, -0.592607, 0.0},
+ {-0.795853, -0.605066, -0.0226607, 0.0},
+ {-0.828661, -0.419471, -0.370628, 0.0},
+ {0.0847218, -0.489815, -0.8677, 0.0},
+ {-0.381405, 0.788019, -0.483276, 0.0},
+ {0.282042, -0.953394, 0.107205, 0.0},
+ {0.530774, 0.847413, 0.0130696, 0.0},
+ {0.0515397, 0.922524, 0.382484, 0.0},
+ {-0.631467, -0.709046, 0.313852, 0.0},
+ {0.688248, 0.517273, 0.508668, 0.0},
+ {0.646689, -0.333782, -0.685845, 0.0},
+ {-0.932528, -0.247532, -0.262906, 0.0},
+ {0.630609, 0.68757, -0.359973, 0.0},
+ {0.577805, -0.394189, 0.714673, 0.0},
+ {-0.887833, -0.437301, -0.14325, 0.0},
+ {0.690982, 0.174003, 0.701617, 0.0},
+ {-0.866701, 0.0118182, 0.498689, 0.0},
+ {-0.482876, 0.727143, 0.487949, 0.0},
+ {-0.577567, 0.682593, -0.447752, 0.0},
+ {0.373768, 0.0982991, 0.922299, 0.0},
+ {0.170744, 0.964243, -0.202687, 0.0},
+ {0.993654, -0.035791, -0.106632, 0.0},
+ {0.587065, 0.4143, -0.695493, 0.0},
+ {-0.396509, 0.26509, -0.878924, 0.0},
+ {-0.0866853, 0.83553, -0.542563, 0.0},
+ {0.923193, 0.133398, -0.360443, 0.0},
+ {0.00379108, -0.258618, 0.965972, 0.0},
+ {0.239144, 0.245154, -0.939526, 0.0},
+ {0.758731, -0.555871, 0.33961, 0.0},
+ {0.295355, 0.309513, 0.903862, 0.0},
+ {0.0531222, -0.91003, -0.411124, 0.0},
+ {0.270452, 0.0229439, -0.96246, 0.0},
+ {0.563634, 0.0324352, 0.825387, 0.0},
+ {0.156326, 0.147392, 0.976646, 0.0},
+ {-0.0410141, 0.981824, 0.185309, 0.0},
+ {-0.385562, -0.576343, -0.720535, 0.0},
+ {0.388281, 0.904441, 0.176702, 0.0},
+ {0.945561, -0.192859, -0.262146, 0.0},
+ {0.844504, 0.520193, 0.127325, 0.0},
+ {0.0330893, 0.999121, -0.0257505, 0.0},
+ {-0.592616, -0.482475, -0.644999, 0.0},
+ {0.539471, 0.631024, -0.557476, 0.0},
+ {0.655851, -0.027319, -0.754396, 0.0},
+ {0.274465, 0.887659, 0.369772, 0.0},
+ {-0.123419, 0.975177, -0.183842, 0.0},
+ {-0.223429, 0.708045, 0.66989, 0.0},
+ {-0.908654, 0.196302, 0.368528, 0.0},
+ {-0.95759, -0.00863708, 0.288005, 0.0},
+ {0.960535, 0.030592, 0.276472, 0.0},
+ {-0.413146, 0.907537, 0.0754161, 0.0},
+ {-0.847992, 0.350849, -0.397259, 0.0},
+ {0.614736, 0.395841, 0.68221, 0.0},
+ {-0.503504, -0.666128, -0.550234, 0.0},
+ {-0.268833, -0.738524, -0.618314, 0.0},
+ {0.792737, -0.60001, -0.107502, 0.0},
+ {-0.637582, 0.508144, -0.579032, 0.0},
+ {0.750105, 0.282165, -0.598101, 0.0},
+ {-0.351199, -0.392294, -0.850155, 0.0},
+ {0.250126, -0.960993, -0.118025, 0.0},
+ {-0.732341, 0.680909, -0.0063274, 0.0},
+ {-0.760674, -0.141009, 0.633634, 0.0},
+ {0.222823, -0.304012, 0.926243, 0.0},
+ {0.209178, 0.505671, 0.836984, 0.0},
+ {0.757914, -0.56629, -0.323857, 0.0},
+ {-0.782926, -0.339196, 0.52151, 0.0},
+ {-0.462952, 0.585565, 0.665424, 0.0},
+ {0.61879, 0.194119, -0.761194, 0.0},
+ {0.741388, -0.276743, 0.611357, 0.0},
+ {0.707571, 0.702621, 0.0752872, 0.0},
+ {0.156562, 0.819977, 0.550569, 0.0},
+ {-0.793606, 0.440216, 0.42, 0.0},
+ {0.234547, 0.885309, -0.401517, 0.0},
+ {0.132598, 0.80115, -0.58359, 0.0},
+ {-0.377899, -0.639179, 0.669808, 0.0},
+ {-0.865993, -0.396465, 0.304748, 0.0},
+ {-0.624815, -0.44283, 0.643046, 0.0},
+ {-0.485705, 0.825614, -0.287146, 0.0},
+ {-0.971788, 0.175535, 0.157529, 0.0},
+ {-0.456027, 0.392629, 0.798675, 0.0},
+ {-0.0104443, 0.521623, -0.853112, 0.0},
+ {-0.660575, -0.74519, 0.091282, 0.0},
+ {-0.0157698, -0.307475, -0.951425, 0.0},
+ {-0.603467, -0.250192, 0.757121, 0.0},
+ {0.506876, 0.25006, 0.824952, 0.0},
+ {0.255404, 0.966794, 0.00884498, 0.0},
+ {0.466764, -0.874228, -0.133625, 0.0},
+ {0.475077, -0.0682351, -0.877295, 0.0},
+ {-0.224967, -0.938972, -0.260233, 0.0},
+ {-0.377929, -0.814757, -0.439705, 0.0},
+ {-0.305847, 0.542333, -0.782517, 0.0},
+ {0.26658, -0.902905, -0.337191, 0.0},
+ {0.0275773, 0.322158, -0.946284, 0.0},
+ {0.0185422, 0.716349, 0.697496, 0.0},
+ {-0.20483, 0.978416, 0.0273371, 0.0},
+ {-0.898276, 0.373969, 0.230752, 0.0},
+ {-0.00909378, 0.546594, 0.837349, 0.0},
+ {0.6602, -0.751089, 0.000959236, 0.0},
+ {0.855301, -0.303056, 0.420259, 0.0},
+ {0.797138, 0.0623013, -0.600574, 0.0},
+ {0.48947, -0.866813, 0.0951509, 0.0},
+ {0.251142, 0.674531, 0.694216, 0.0},
+ {-0.578422, -0.737373, -0.348867, 0.0},
+ {-0.254689, -0.514807, 0.818601, 0.0},
+ {0.374972, 0.761612, 0.528529, 0.0},
+ {0.640303, -0.734271, -0.225517, 0.0},
+ {-0.638076, 0.285527, 0.715075, 0.0},
+ {0.772956, -0.15984, -0.613995, 0.0},
+ {0.798217, -0.590628, 0.118356, 0.0},
+ {-0.986276, -0.0578337, -0.154644, 0.0},
+ {-0.312988, -0.94549, 0.0899272, 0.0},
+ {-0.497338, 0.178325, 0.849032, 0.0},
+ {-0.101136, -0.981014, 0.165477, 0.0},
+ {-0.521688, 0.0553434, -0.851339, 0.0},
+ {-0.786182, -0.583814, 0.202678, 0.0},
+ {-0.565191, 0.821858, -0.0714658, 0.0},
+ {0.437895, 0.152598, -0.885981, 0.0},
+ {-0.92394, 0.353436, -0.14635, 0.0},
+ {0.212189, -0.815162, -0.538969, 0.0},
+ {-0.859262, 0.143405, -0.491024, 0.0},
+ {0.991353, 0.112814, 0.0670273, 0.0},
+ {0.0337884, -0.979891, -0.196654, 0.0}
+ };
+
+ private VectorTable()
+ {
+
+ }
+
+ public static double getRandomVectors(int a, int b)
+ {
+ return randomVectors[a][b];
+ }
+
+
+
+}
+
diff --git a/src/libnoiseforjava/exception/ExceptionInvalidParam.java b/src/libnoiseforjava/exception/ExceptionInvalidParam.java new file mode 100644 index 0000000..f79bf91 --- /dev/null +++ b/src/libnoiseforjava/exception/ExceptionInvalidParam.java @@ -0,0 +1,42 @@ +/*
+ * Copyright (C) 2003, 2004 Jason Bevins (original libnoise code)
+ * Copyright 2010 Thomas J. Hodge (java port of libnoise)
+ *
+ * This file is part of libnoiseforjava.
+ *
+ * libnoiseforjava is a Java port of the C++ library libnoise, which may be found at
+ * http://libnoise.sourceforge.net/. libnoise was developed by Jason Bevins, who may be
+ * contacted at [email protected] (for great email, take off every 'zig').
+ * Porting to Java was done by Thomas Hodge, who may be contacted at
+ * [email protected] (remove every 'zag').
+ *
+ * libnoiseforjava is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * libnoiseforjava is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * libnoiseforjava. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package libnoiseforjava.exception;
+
+public class ExceptionInvalidParam extends Exception
+{
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 5603051793321603318L;
+
+ public ExceptionInvalidParam(String message)
+ {
+ super(message);
+ }
+
+}
+
diff --git a/src/libnoiseforjava/exception/ExceptionNoModule.java b/src/libnoiseforjava/exception/ExceptionNoModule.java new file mode 100644 index 0000000..c6dccd6 --- /dev/null +++ b/src/libnoiseforjava/exception/ExceptionNoModule.java @@ -0,0 +1,41 @@ +/*
+ * Copyright (C) 2003, 2004 Jason Bevins (original libnoise code)
+ * Copyright 2010 Thomas J. Hodge (java port of libnoise)
+ *
+ * This file is part of libnoiseforjava.
+ *
+ * libnoiseforjava is a Java port of the C++ library libnoise, which may be found at
+ * http://libnoise.sourceforge.net/. libnoise was developed by Jason Bevins, who may be
+ * contacted at [email protected] (for great email, take off every 'zig').
+ * Porting to Java was done by Thomas Hodge, who may be contacted at
+ * [email protected] (remove every 'zag').
+ *
+ * libnoiseforjava is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * libnoiseforjava is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * libnoiseforjava. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package libnoiseforjava.exception;
+
+public class ExceptionNoModule extends Exception
+{
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = -4820882012470782847L;
+
+ public ExceptionNoModule(String message)
+ {
+ super(message);
+ }
+
+}
diff --git a/src/libnoiseforjava/model/Cylinder.java b/src/libnoiseforjava/model/Cylinder.java new file mode 100644 index 0000000..04647b7 --- /dev/null +++ b/src/libnoiseforjava/model/Cylinder.java @@ -0,0 +1,115 @@ +/*
+ * Copyright (C) 2003, 2004 Jason Bevins (original libnoise code)
+ * Copyright 2010 Thomas J. Hodge (java port of libnoise)
+ *
+ * This file is part of libnoiseforjava.
+ *
+ * libnoiseforjava is a Java port of the C++ library libnoise, which may be found at
+ * http://libnoise.sourceforge.net/. libnoise was developed by Jason Bevins, who may be
+ * contacted at [email protected] (for great email, take off every 'zig').
+ * Porting to Java was done by Thomas Hodge, who may be contacted at
+ * [email protected] (remove every 'zag').
+ *
+ * libnoiseforjava is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * libnoiseforjava is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * libnoiseforjava. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package libnoiseforjava.model;
+
+import libnoiseforjava.module.ModuleBase;
+
+public class Cylinder
+{
+ /// Model that defines the surface of a cylinder.
+ ///
+ /// @image html modelcylinder.png
+ ///
+ /// This model returns an output value from a noise module given the
+ /// coordinates of an input value located on the surface of a cylinder.
+ ///
+ /// To generate an output value, pass the (angle, height) coordinates of
+ /// an input value to the GetValue() method.
+ ///
+ /// This model is useful for creating:
+ /// - seamless textures that can be mapped onto a cylinder
+ ///
+ /// This cylinder has a radius of 1.0 unit and has infinite height. It is
+ /// oriented along the @a y axis. Its center is located at the origin.
+
+
+
+ /// A pointer to the noise module used to generate the output values.
+ ModuleBase module;
+
+ public Cylinder ()
+ {
+ module = new ModuleBase(1);
+ }
+
+ Cylinder (ModuleBase module)
+ {
+ this.module = module;
+ }
+
+ /// Returns the output value from the noise module given the
+ /// (angle, height) coordinates of the specified input value located
+ /// on the surface of the cylinder.
+ ///
+ /// @param angle The angle around the cylinder's center, in degrees.
+ /// @param height The height along the @a y axis.
+ ///
+ /// @returns The output value from the noise module.
+ ///
+ /// @pre A noise module was passed to the setModule() method.
+ ///
+ /// This output value is generated by the noise module passed to the
+ /// SetModule() method.
+ ///
+ /// This cylinder has a radius of 1.0 unit and has infinite height.
+ /// It is oriented along the @a y axis. Its center is located at the
+ /// origin.
+ public double getValue (double angle, double height)
+ {
+ assert (module != null);
+
+ double x, y, z;
+ x = Math.cos(Math.toRadians(angle));
+ y = height;
+ z = Math.sin(Math.toRadians(angle));
+ return module.getValue (x, y, z);
+ }
+
+ /// Returns the noise module that is used to generate the output
+ /// values.
+ ///
+ /// @returns A reference to the noise module.
+ ///
+ /// @pre A noise module was passed to the setModule() method.
+ public ModuleBase getModule ()
+ {
+ assert (module != null);
+ return module;
+ }
+
+ /// Sets the noise module that is used to generate the output values.
+ ///
+ /// @param module The noise module that is used to generate the output
+ /// values.
+ ///
+ /// This noise module must exist for the lifetime of this object,
+ /// until you pass a new noise module to this method.
+ public void setModule (ModuleBase module)
+ {
+ this.module = module;
+ }
+
+}
diff --git a/src/libnoiseforjava/model/Line.java b/src/libnoiseforjava/model/Line.java new file mode 100644 index 0000000..7509f90 --- /dev/null +++ b/src/libnoiseforjava/model/Line.java @@ -0,0 +1,264 @@ +/*
+ * Copyright (C) 2003, 2004 Jason Bevins (original libnoise code)
+ * Copyright 2010 Thomas J. Hodge (java port of libnoise)
+ *
+ * This file is part of libnoiseforjava.
+ *
+ * libnoiseforjava is a Java port of the C++ library libnoise, which may be found at
+ * http://libnoise.sourceforge.net/. libnoise was developed by Jason Bevins, who may be
+ * contacted at [email protected] (for great email, take off every 'zig').
+ * Porting to Java was done by Thomas Hodge, who may be contacted at
+ * [email protected] (remove every 'zag').
+ *
+ * libnoiseforjava is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * libnoiseforjava is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * libnoiseforjava. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package libnoiseforjava.model;
+
+import libnoiseforjava.module.ModuleBase;
+
+public class Line
+{
+
+ /// Model that defines the displacement of a line segment.
+ ///
+ /// This model returns an output value from a noise module given the
+ /// one-dimensional coordinate of an input value located on a line
+ /// segment, which can be used as displacements.
+ ///
+ /// This class is useful for creating:
+ /// - roads and rivers
+ /// - disaffected college students
+ ///
+ /// To generate an output value, pass an input value between 0.0 and 1.0
+ /// to the getValue() method. 0.0 represents the start position of the
+ /// line segment and 1.0 represents the end position of the line segment.
+
+
+ /// A flag that specifies whether the value is to be attenuated
+ /// (moved toward 0.0) as the ends of the line segment are approached.
+ boolean attenuate;
+
+ /// A pointer to the noise module used to generate the output values.
+ ModuleBase module;
+
+ /// @a x coordinate of the start of the line segment.
+ double x0;
+
+ /// @a x coordinate of the end of the line segment.
+ double x1;
+
+ /// @a y coordinate of the start of the line segment.
+ double y0;
+
+ /// @a y coordinate of the end of the line segment.
+ double y1;
+
+ /// @a z coordinate of the start of the line segment.
+ double z0;
+
+ /// @a z coordinate of the end of the line segment.
+ double z1;
+
+ Line ()
+ {
+ attenuate = true;
+ module = new ModuleBase(1);
+ x0 = 0.0;
+ x1 = 1.0;
+ y0 = 0.0;
+ y1 = 1.0;
+ z0 = 0.0;
+ z1 = 1.0;
+ }
+
+ Line (ModuleBase module)
+ {
+ attenuate = true;
+ this.module = module;
+ x0 = 0.0;
+ x1 = 1.0;
+ y0 = 0.0;
+ y1 = 1.0;
+ z0 = 0.0;
+ z1 = 1.0;
+ }
+
+ /// Returns the output value from the noise module given the
+ /// one-dimensional coordinate of the specified input value located
+ /// on the line segment.
+ ///
+ /// @param p The distance along the line segment (ranges from 0.0
+ /// to 1.0)
+ ///
+ /// @returns The output value from the noise module.
+ ///
+ /// @pre A noise module was passed to the setModule() method.
+ /// @pre The start and end points of the line segment were specified.
+ ///
+ /// The output value is generated by the noise module passed to the
+ /// setModule() method. This value may be attenuated (moved toward
+ /// 0.0) as @a p approaches either end of the line segment; this is
+ /// the default behavior.
+ ///
+ /// If the value is not to be attenuated, @a p can safely range
+ /// outside the 0.0 to 1.0 range; the output value will be
+ /// extrapolated along the line that this segment is part of.
+ public double getValue (double p)
+ {
+ assert (module != null);
+
+ double x = (x1 - x0) * p + x0;
+ double y = (y1 - y0) * p + y0;
+ double z = (z1 - z0) * p + z0;
+ double value = module.getValue (x, y, z);
+
+ if (attenuate)
+ return p * (1.0 - p) * 4 * value;
+ else
+ return value;
+ }
+
+ /// Returns a flag indicating whether the output value is to be
+ /// attenuated (moved toward 0.0) as the ends of the line segment are
+ /// approached by the input value.
+ ///
+ /// @returns
+ /// - @a true if the value is to be attenuated
+ /// - @a false if not.
+ public boolean getAttenuate ()
+ {
+ return attenuate;
+ }
+
+ /// Returns the noise module that is used to generate the output
+ /// values.
+ ///
+ /// @returns A reference to the noise module.
+ ///
+ /// @pre A noise module was passed to the setModule() method.
+ public ModuleBase getModule ()
+ {
+ assert (module != null);
+ return module;
+ }
+
+ /// Sets a flag indicating that the output value is to be attenuated
+ /// (moved toward 0.0) as the ends of the line segment are approached.
+ ///
+ /// @param att A flag that specifies whether the output value is to be
+ /// attenuated.
+ public void setAttenuate (boolean att)
+ {
+ attenuate = att;
+ }
+
+ /// Sets the position ( @a x, @a y, @a z ) of the end of the line
+ /// segment to choose values along.
+ ///
+ /// @param x x coordinate of the end position.
+ /// @param y y coordinate of the end position.
+ /// @param z z coordinate of the end position.
+ public void setEndPoint (double x, double y, double z)
+ {
+ x1 = x;
+ y1 = y;
+ z1 = z;
+ }
+
+ /// Sets the noise module that is used to generate the output values.
+ ///
+ /// @param module The noise module that is used to generate the output
+ /// values.
+ ///
+ /// This noise module must exist for the lifetime of this object,
+ /// until you pass a new noise module to this method.
+ public void setModule (ModuleBase module)
+ {
+ this.module = module;
+ }
+
+ /// Sets the position ( @a x, @a y, @a z ) of the start of the line
+ /// segment to choose values along.
+ ///
+ /// @param x x coordinate of the start position.
+ /// @param y y coordinate of the start position.
+ /// @param z z coordinate of the start position.
+ public void setStartPoint (double x, double y, double z)
+ {
+ x0 = x;
+ y0 = y;
+ z0 = z;
+ }
+
+ public double getX0()
+ {
+ return x0;
+ }
+
+ public double getX1()
+ {
+ return x1;
+ }
+
+ public double getY0()
+ {
+ return y0;
+ }
+
+ public double getY1()
+ {
+ return y1;
+ }
+
+ public double getZ0()
+ {
+ return z0;
+ }
+
+ public double getZ1()
+ {
+ return z1;
+ }
+
+ public void setX0(double x0)
+ {
+ this.x0 = x0;
+ }
+
+ public void setX1(double x1)
+ {
+ this.x1 = x1;
+ }
+
+ public void setY0(double y0)
+ {
+ this.y0 = y0;
+ }
+
+ public void setY1(double y1)
+ {
+ this.y1 = y1;
+ }
+
+ public void setZ0(double z0)
+ {
+ this.z0 = z0;
+ }
+
+ public void setZ1(double z1)
+ {
+ this.z1 = z1;
+ }
+
+}
diff --git a/src/libnoiseforjava/model/Plane.java b/src/libnoiseforjava/model/Plane.java new file mode 100644 index 0000000..4d498f4 --- /dev/null +++ b/src/libnoiseforjava/model/Plane.java @@ -0,0 +1,105 @@ +/*
+ * Copyright (C) 2003, 2004 Jason Bevins (original libnoise code)
+ * Copyright 2010 Thomas J. Hodge (java port of libnoise)
+ *
+ * This file is part of libnoiseforjava.
+ *
+ * libnoiseforjava is a Java port of the C++ library libnoise, which may be found at
+ * http://libnoise.sourceforge.net/. libnoise was developed by Jason Bevins, who may be
+ * contacted at [email protected] (for great email, take off every 'zig').
+ * Porting to Java was done by Thomas Hodge, who may be contacted at
+ * [email protected] (remove every 'zag').
+ *
+ * libnoiseforjava is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * libnoiseforjava is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * libnoiseforjava. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package libnoiseforjava.model;
+
+import libnoiseforjava.module.ModuleBase;
+
+public class Plane
+{
+ /// Model that defines the surface of a plane.
+ ///
+ /// This model returns an output value from a noise module given the
+ /// coordinates of an input value located on the surface of an ( @a x,
+ /// @a z ) plane.
+ ///
+ /// To generate an output value, pass the ( @a x, @a z ) coordinates of
+ /// an input value to the GetValue() method.
+ ///
+ /// This model is useful for creating:
+ /// - two-dimensional textures
+ /// - terrain height maps for local areas
+ ///
+ /// This plane extends infinitely in both directions.
+
+
+ /// A pointer to the noise module used to generate the output values.
+ ModuleBase module;
+
+ public Plane ()
+ {
+ module = new ModuleBase(1);
+ }
+
+ public Plane (ModuleBase module)
+ {
+ this.module = module;
+ }
+
+ /// Returns the output value from the noise module given the
+ /// ( @a x, @a z ) coordinates of the specified input value located
+ /// on the surface of the plane.
+ ///
+ /// @param x The @a x coordinate of the input value.
+ /// @param z The @a z coordinate of the input value.
+ ///
+ /// @returns The output value from the noise module.
+ ///
+ /// @pre A noise module was passed to the setModule() method.
+ ///
+ /// This output value is generated by the noise module passed to the
+ /// setModule() method.
+ public double getValue (double x, double z)
+ {
+ assert (module != null);
+
+ return module.getValue (x, 0, z);
+ }
+
+ /// Returns the noise module that is used to generate the output
+ /// values.
+ ///
+ /// @returns A reference to the noise module.
+ ///
+ /// @pre A noise module was passed to the setModule() method.
+ public ModuleBase getModule ()
+ {
+ assert (module != null);
+ return module;
+ }
+
+ /// Sets the noise module that is used to generate the output values.
+ ///
+ /// @param module The noise module that is used to generate the output
+ /// values.
+ ///
+ /// This noise module must exist for the lifetime of this object,
+ /// until you pass a new noise module to this method.
+ public void setModule (ModuleBase module)
+ {
+ this.module = module;
+ }
+
+}
diff --git a/src/libnoiseforjava/model/Sphere.java b/src/libnoiseforjava/model/Sphere.java new file mode 100644 index 0000000..43d2bb9 --- /dev/null +++ b/src/libnoiseforjava/model/Sphere.java @@ -0,0 +1,118 @@ +/*
+ * Copyright (C) 2003, 2004 Jason Bevins (original libnoise code)
+ * Copyright 2010 Thomas J. Hodge (java port of libnoise)
+ *
+ * This file is part of libnoiseforjava.
+ *
+ * libnoiseforjava is a Java port of the C++ library libnoise, which may be found at
+ * http://libnoise.sourceforge.net/. libnoise was developed by Jason Bevins, who may be
+ * contacted at [email protected] (for great email, take off every 'zig').
+ * Porting to Java was done by Thomas Hodge, who may be contacted at
+ * [email protected] (remove every 'zag').
+ *
+ * libnoiseforjava is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * libnoiseforjava is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * libnoiseforjava. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package libnoiseforjava.model;
+
+import libnoiseforjava.module.ModuleBase;
+
+public class Sphere
+{
+ /// Model that defines the surface of a sphere.
+ ///
+ /// @image html modelsphere.png
+ ///
+ /// This model returns an output value from a noise module given the
+ /// coordinates of an input value located on the surface of a sphere.
+ ///
+ /// To generate an output value, pass the (latitude, longitude)
+ /// coordinates of an input value to the getValue() method.
+ ///
+ /// This model is useful for creating:
+ /// - seamless textures that can be mapped onto a sphere
+ /// - terrain height maps for entire planets
+ ///
+ /// This sphere has a radius of 1.0 unit and its center is located at
+ /// the origin.
+
+ /// A pointer to the noise module used to generate the output values.
+ ModuleBase module;
+
+
+ public Sphere()
+ {
+ module = new ModuleBase(1);
+ }
+
+ Sphere(ModuleBase module)
+ {
+ this.module = module;
+ }
+
+ /// Returns the output value from the noise module given the
+ /// (latitude, longitude) coordinates of the specified input value
+ /// located on the surface of the sphere.
+ ///
+ /// @param lat The latitude of the input value, in degrees.
+ /// @param lon The longitude of the input value, in degrees.
+ ///
+ /// @returns The output value from the noise module.
+ ///
+ /// @pre A noise module was passed to the setModule() method.
+ ///
+ /// This output value is generated by the noise module passed to the
+ /// setModule() method.
+ ///
+ /// Use a negative latitude if the input value is located on the
+ /// southern hemisphere.
+ ///
+ /// Use a negative longitude if the input value is located on the
+ /// western hemisphere.
+ public double getValue (double lat, double lon)
+ {
+ assert (module != null);
+
+ double x, y, z;
+ double r = Math.cos(Math.toRadians(lat));
+ x = r * Math.cos (Math.toRadians(lon));
+ y = Math.sin (Math.toRadians(lat));
+ z = r * Math.sin (Math.toRadians(lon));
+ return module.getValue (x, y, z);
+ }
+
+ /// Returns the noise module that is used to generate the output
+ /// values.
+ ///
+ /// @returns A reference to the noise module.
+ ///
+ /// @pre A noise module was passed to the setModule() method.
+ public ModuleBase getModule ()
+ {
+ assert (module != null);
+ return module;
+ }
+
+ /// Sets the noise module that is used to generate the output values.
+ ///
+ /// @param module The noise module that is used to generate the output
+ /// values.
+ ///
+ /// This noise module must exist for the lifetime of this object,
+ /// until you pass a new noise module to this method.
+ public void setModule (ModuleBase module)
+ {
+ this.module = module;
+ }
+
+}
diff --git a/src/libnoiseforjava/module/Abs.java b/src/libnoiseforjava/module/Abs.java new file mode 100644 index 0000000..89e5c22 --- /dev/null +++ b/src/libnoiseforjava/module/Abs.java @@ -0,0 +1,52 @@ +/*
+ * Copyright (C) 2003, 2004 Jason Bevins (original libnoise code)
+ * Copyright 2010 Thomas J. Hodge (java port of libnoise)
+ *
+ * This file is part of libnoiseforjava.
+ *
+ * libnoiseforjava is a Java port of the C++ library libnoise, which may be found at
+ * http://libnoise.sourceforge.net/. libnoise was developed by Jason Bevins, who may be
+ * contacted at [email protected] (for great email, take off every 'zig').
+ * Porting to Java was done by Thomas Hodge, who may be contacted at
+ * [email protected] (remove every 'zag').
+ *
+ * libnoiseforjava is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * libnoiseforjava is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * libnoiseforjava. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package libnoiseforjava.module;
+
+import libnoiseforjava.exception.ExceptionInvalidParam;
+
+public class Abs extends ModuleBase
+{
+ /// Noise module that outputs the absolute value of the output value from
+ /// a source module.
+ ///
+ /// @image html moduleabs.png
+ ///
+ /// This noise module requires one source module.
+
+ Abs (ModuleBase sourceModule) throws ExceptionInvalidParam
+ {
+ super(1);
+ setSourceModule(0, sourceModule);
+ }
+
+ public double getValue (double x, double y, double z)
+ {
+ assert (this.sourceModules[0] != null);
+
+ return Math.abs(this.sourceModules[0].getValue (x, y, z));
+ }
+
+}
diff --git a/src/libnoiseforjava/module/Add.java b/src/libnoiseforjava/module/Add.java new file mode 100644 index 0000000..f06c895 --- /dev/null +++ b/src/libnoiseforjava/module/Add.java @@ -0,0 +1,53 @@ +/*
+ * Copyright (C) 2003, 2004 Jason Bevins (original libnoise code)
+ * Copyright 2010 Thomas J. Hodge (java port of libnoise)
+ *
+ * This file is part of libnoiseforjava.
+ *
+ * libnoiseforjava is a Java port of the C++ library libnoise, which may be found at
+ * http://libnoise.sourceforge.net/. libnoise was developed by Jason Bevins, who may be
+ * contacted at [email protected] (for great email, take off every 'zig').
+ * Porting to Java was done by Thomas Hodge, who may be contacted at
+ * [email protected] (remove every 'zag').
+ *
+ * libnoiseforjava is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * libnoiseforjava is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * libnoiseforjava. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package libnoiseforjava.module;
+
+import libnoiseforjava.exception.ExceptionInvalidParam;
+
+public class Add extends ModuleBase
+{
+ /// Noise module that outputs the additive value of the output value from
+ /// two source modules.
+ ///
+ /// This noise module requires two source modules.
+
+ public Add (ModuleBase sourceModuleOne, ModuleBase sourceModuleTwo) throws ExceptionInvalidParam
+ {
+ super(2);
+ setSourceModule(0, sourceModuleOne);
+ setSourceModule(1, sourceModuleTwo);
+ }
+
+ public double getValue (double x, double y, double z)
+ {
+ assert (sourceModules[0] != null);
+ assert (sourceModules[1] != null);
+
+ return sourceModules[0].getValue (x, y, z)
+ + sourceModules[1].getValue (x, y, z);
+ }
+
+}
diff --git a/src/libnoiseforjava/module/Billow.java b/src/libnoiseforjava/module/Billow.java new file mode 100644 index 0000000..047c8df --- /dev/null +++ b/src/libnoiseforjava/module/Billow.java @@ -0,0 +1,184 @@ +/*
+ * Copyright (C) 2003, 2004 Jason Bevins (original libnoise code)
+ * Copyright 2010 Thomas J. Hodge (java port of libnoise)
+ *
+ * This file is part of libnoiseforjava.
+ *
+ * libnoiseforjava is a Java port of the C++ library libnoise, which may be found at
+ * http://libnoise.sourceforge.net/. libnoise was developed by Jason Bevins, who may be
+ * contacted at [email protected] (for great email, take off every 'zig').
+ * Porting to Java was done by Thomas Hodge, who may be contacted at
+ * [email protected] (remove every 'zag').
+ *
+ * libnoiseforjava is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * libnoiseforjava is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * libnoiseforjava. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package libnoiseforjava.module;
+
+import libnoiseforjava.NoiseGen;
+import libnoiseforjava.NoiseGen.NoiseQuality;
+
+public class Billow extends ModuleBase
+{
+ /// Noise module that outputs three-dimensional "billowy" noise.
+ ///
+ /// @image html modulebillow.png
+ ///
+ /// This noise module generates "billowy" noise suitable for clouds and
+ /// rocks.
+ ///
+ /// This noise module is nearly identical to noise::module::Perlin except
+ /// this noise module modifies each octave with an absolute-value
+ /// function. See the documentation of noise::module::Perlin for more
+ /// information.
+
+
+ /// Default frequency for the Billow noise module.
+ static final double DEFAULT_BILLOW_FREQUENCY = 1.0;
+
+ /// Default lacunarity for the Billow noise module.
+ static final double DEFAULT_BILLOW_LACUNARITY = 2.0;
+
+ /// Default number of octaves for the the noise::module::Billow noise
+ /// module.
+ static final int DEFAULT_BILLOW_OCTAVE_COUNT = 6;
+
+ /// Default persistence value for the the noise::module::Billow noise
+ /// module.
+ static final double DEFAULT_BILLOW_PERSISTENCE = 0.5;
+
+ /// Default noise quality for the the noise::module::Billow noise module.
+ static final NoiseQuality DEFAULT_BILLOW_QUALITY = NoiseQuality.QUALITY_STD;
+
+ /// Default noise seed for the the noise::module::Billow noise module.
+ static final int DEFAULT_BILLOW_SEED = 0;
+
+ /// Maximum number of octaves for the the noise::module::Billow noise
+ /// module.
+ static final int BILLOW_MAX_OCTAVE = 30;
+
+ double frequency, lacunarity, persistence;
+ int octaveCount, seed;
+ NoiseQuality noiseQuality;
+
+ public Billow ()
+ {
+ super(0);
+ frequency = DEFAULT_BILLOW_FREQUENCY;
+ lacunarity = DEFAULT_BILLOW_LACUNARITY;
+ noiseQuality = DEFAULT_BILLOW_QUALITY;
+ octaveCount = DEFAULT_BILLOW_OCTAVE_COUNT;
+ persistence = DEFAULT_BILLOW_PERSISTENCE;
+ seed = DEFAULT_BILLOW_SEED;
+ }
+
+ public double getValue (double x, double y, double z)
+ {
+ double value = 0.0;
+ double signal = 0.0;
+ double curPersistence = 1.0;
+ double nx, ny, nz;
+ int calcSeed;
+
+ x *= frequency;
+ y *= frequency;
+ z *= frequency;
+
+ for (int curOctave = 0; curOctave < octaveCount; curOctave++)
+ {
+ // Make sure that these floating-point values have the same range as a 32-
+ // bit integer so that we can pass them to the coherent-noise functions.
+ nx = NoiseGen.MakeInt32Range (x);
+ ny = NoiseGen.MakeInt32Range (y);
+ nz = NoiseGen.MakeInt32Range (z);
+
+ // Get the coherent-noise value from the input value and add it to the
+ // final result.
+ calcSeed = (seed + curOctave) & 0xffffffff;
+ signal = NoiseGen.GradientCoherentNoise3D (nx, ny, nz, calcSeed, noiseQuality);
+ signal = 2.0 * Math.abs(signal) - 1.0;
+ value += signal * curPersistence;
+
+ // Prepare the next octave.
+ x *= lacunarity;
+ y *= lacunarity;
+ z *= lacunarity;
+ curPersistence *= persistence;
+ }
+
+ value += 0.5;
+
+ return value;
+ }
+
+ public double getFrequency()
+ {
+ return frequency;
+ }
+
+ public double getLacunarity()
+ {
+ return lacunarity;
+ }
+
+ public double getPersistence()
+ {
+ return persistence;
+ }
+
+ public int getOctaveCount()
+ {
+ return octaveCount;
+ }
+
+ public int getSeed()
+ {
+ return seed;
+ }
+
+ public NoiseQuality getNoiseQuality()
+ {
+ return noiseQuality;
+ }
+
+ public void setFrequency(double frequency)
+ {
+ this.frequency = frequency;
+ }
+
+ public void setLacunarity(double lacunarity)
+ {
+ this.lacunarity = lacunarity;
+ }
+
+ public void setPersistence(double persistence)
+ {
+ this.persistence = persistence;
+ }
+
+ public void setOctaveCount(int octaveCount)
+ {
+ this.octaveCount = octaveCount;
+ }
+
+ public void setSeed(int seed)
+ {
+ this.seed = seed;
+ }
+
+ public void setNoiseQuality(NoiseQuality noiseQuality)
+ {
+ this.noiseQuality = noiseQuality;
+ }
+
+}
diff --git a/src/libnoiseforjava/module/Blend.java b/src/libnoiseforjava/module/Blend.java new file mode 100644 index 0000000..5e442b7 --- /dev/null +++ b/src/libnoiseforjava/module/Blend.java @@ -0,0 +1,79 @@ +/*
+ * Copyright (C) 2003, 2004 Jason Bevins (original libnoise code)
+ * Copyright 2010 Thomas J. Hodge (java port of libnoise)
+ *
+ * This file is part of libnoiseforjava.
+ *
+ * libnoiseforjava is a Java port of the C++ library libnoise, which may be found at
+ * http://libnoise.sourceforge.net/. libnoise was developed by Jason Bevins, who may be
+ * contacted at [email protected] (for great email, take off every 'zig').
+ * Porting to Java was done by Thomas Hodge, who may be contacted at
+ * [email protected] (remove every 'zag').
+ *
+ * libnoiseforjava is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * libnoiseforjava is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * libnoiseforjava. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package libnoiseforjava.module;
+
+import libnoiseforjava.Interp;
+import libnoiseforjava.exception.ExceptionInvalidParam;
+
+public class Blend extends ModuleBase
+{
+ /// Noise module that outputs a weighted blend of the output values from
+ /// two source modules given the output value supplied by a control module.
+ ///
+ /// Unlike most other noise modules, the index value assigned to a source
+ /// module determines its role in the blending operation:
+ /// - Source module 0 outputs one of the
+ /// values to blend.
+ /// - Source module 1 outputs one of the
+ /// values to blend.
+ /// - Source module 2 is known as the <i>control
+ /// module</i>. The control module determines the weight of the
+ /// blending operation. Negative values weigh the blend towards the
+ /// output value from the source module with an index value of 0.
+ /// Positive values weigh the blend towards the output value from the
+ /// source module with an index value of 1.
+ ///
+ /// An application can pass the control module to the setControlModule()
+ /// method instead of the setSourceModule() method. This may make the
+ /// application code easier to read.
+ ///
+ /// This noise module uses linear interpolation to perform the blending
+ /// operation.
+ ///
+ /// This noise module requires three source modules.
+
+ public Blend (ModuleBase sourceModuleOne, ModuleBase sourceModuleTwo,
+ ModuleBase sourceModuleThree) throws ExceptionInvalidParam
+ {
+ super(3);
+ setSourceModule(0, sourceModuleOne);
+ setSourceModule(1, sourceModuleTwo);
+ setSourceModule(2, sourceModuleThree);
+ }
+
+ public double getValue (double x, double y, double z)
+ {
+ assert (sourceModules[0] != null);
+ assert (sourceModules[1] != null);
+ assert (sourceModules[2] != null);
+
+ double v0 = sourceModules[0].getValue (x, y, z);
+ double v1 = sourceModules[1].getValue (x, y, z);
+ double alpha = (sourceModules[2].getValue (x, y, z) + 1.0) / 2.0;
+
+ return Interp.linearInterp (v0, v1, alpha);
+ }
+}
diff --git a/src/libnoiseforjava/module/Cached.java b/src/libnoiseforjava/module/Cached.java new file mode 100644 index 0000000..3afab4c --- /dev/null +++ b/src/libnoiseforjava/module/Cached.java @@ -0,0 +1,97 @@ +/*
+ * Copyright (C) 2003, 2004 Jason Bevins (original libnoise code)
+ * Copyright 2010 Thomas J. Hodge (java port of libnoise)
+ *
+ * This file is part of libnoiseforjava.
+ *
+ * libnoiseforjava is a Java port of the C++ library libnoise, which may be found at
+ * http://libnoise.sourceforge.net/. libnoise was developed by Jason Bevins, who may be
+ * contacted at [email protected] (for great email, take off every 'zig').
+ * Porting to Java was done by Thomas Hodge, who may be contacted at
+ * [email protected] (remove every 'zag').
+ *
+ * libnoiseforjava is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * libnoiseforjava is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * libnoiseforjava. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package libnoiseforjava.module;
+
+import libnoiseforjava.exception.ExceptionInvalidParam;
+
+public class Cached extends ModuleBase
+{
+ /// Noise module that caches the last output value generated by a source
+ /// module.
+ ///
+ /// If an application passes an input value to the getValue() method that
+ /// differs from the previously passed-in input value, this noise module
+ /// instructs the source module to calculate the output value. This
+ /// value, as well as the ( @a x, @a y, @a z ) coordinates of the input
+ /// value, are stored (cached) in this noise module.
+ ///
+ /// If the application passes an input value to the getValue() method
+ /// that is equal to the previously passed-in input value, this noise
+ /// module returns the cached output value without having the source
+ /// module recalculate the output value.
+ ///
+ /// If an application passes a new source module to the setSourceModule()
+ /// method, the cache is invalidated.
+ ///
+ /// Caching a noise module is useful if it is used as a source module for
+ /// multiple noise modules. If a source module is not cached, the source
+ /// module will redundantly calculate the same output value once for each
+ /// noise module in which it is included.
+ ///
+ /// This noise module requires one source module.
+
+ /// The cached output value at the cached input value.
+ double cachedValue;
+
+ /// Determines if a cached output value is stored in this noise module.
+ boolean isCached;
+
+ /// @a x coordinate of the cached input value.
+ double xCache;
+
+ /// @a y coordinate of the cached input value.
+ double yCache;
+
+ /// @a z coordinate of the cached input value.
+ double zCache;
+
+ public Cached(ModuleBase sourceModule) throws ExceptionInvalidParam
+ {
+ super(1);
+ setSourceModule(0, sourceModule);
+ isCached = false;
+ }
+
+ public double getValue (double x, double y, double z)
+ {
+ assert (sourceModules[0] != null);
+
+ if (!(isCached && x == xCache && y == yCache && z == zCache))
+ {
+ cachedValue = sourceModules[0].getValue (x, y, z);
+ xCache = x;
+ yCache = y;
+ zCache = z;
+ }
+
+ isCached = true;
+
+ return cachedValue;
+ }
+
+
+
+}
diff --git a/src/libnoiseforjava/module/Checkerboard.java b/src/libnoiseforjava/module/Checkerboard.java new file mode 100644 index 0000000..d9f4e1f --- /dev/null +++ b/src/libnoiseforjava/module/Checkerboard.java @@ -0,0 +1,62 @@ +/*
+ * Copyright (C) 2003, 2004 Jason Bevins (original libnoise code)
+ * Copyright 2010 Thomas J. Hodge (java port of libnoise)
+ *
+ * This file is part of libnoiseforjava.
+ *
+ * libnoiseforjava is a Java port of the C++ library libnoise, which may be found at
+ * http://libnoise.sourceforge.net/. libnoise was developed by Jason Bevins, who may be
+ * contacted at [email protected] (for great email, take off every 'zig').
+ * Porting to Java was done by Thomas Hodge, who may be contacted at
+ * [email protected] (remove every 'zag').
+ *
+ * libnoiseforjava is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * libnoiseforjava is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * libnoiseforjava. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package libnoiseforjava.module;
+
+import libnoiseforjava.NoiseGen;
+
+public class Checkerboard extends ModuleBase
+{
+ /// Noise module that outputs a checkerboard pattern.
+ ///
+ /// This noise module outputs unit-sized blocks of alternating values.
+ /// The values of these blocks alternate between -1.0 and +1.0.
+ ///
+ /// This noise module is not really useful by itself, but it is often used
+ /// for debugging purposes.
+ ///
+ /// This noise module does not require any source modules.
+
+ public Checkerboard()
+ {
+ super(0);
+ }
+
+ public double getValue (double x, double y, double z)
+ {
+ int ix = (int)(Math.floor(NoiseGen.MakeInt32Range (x)));
+ int iy = (int)(Math.floor(NoiseGen.MakeInt32Range (y)));
+ int iz = (int)(Math.floor(NoiseGen.MakeInt32Range (z)));
+
+ // original was
+ //(ix & 1 ^ iy & 1 ^ iz & 1)
+ // not certain if this duplicates it or not
+ if ((ix%2 == 1) ^ (iy%2 == 1) ^ (iz%2 == 1))
+ return -1.0;
+ else
+ return 1.0;
+ }
+}
+
diff --git a/src/libnoiseforjava/module/Clamp.java b/src/libnoiseforjava/module/Clamp.java new file mode 100644 index 0000000..3ad6d39 --- /dev/null +++ b/src/libnoiseforjava/module/Clamp.java @@ -0,0 +1,90 @@ +/*
+ * Copyright (C) 2003, 2004 Jason Bevins (original libnoise code)
+ * Copyright 2010 Thomas J. Hodge (java port of libnoise)
+ *
+ * This file is part of libnoiseforjava.
+ *
+ * libnoiseforjava is a Java port of the C++ library libnoise, which may be found at
+ * http://libnoise.sourceforge.net/. libnoise was developed by Jason Bevins, who may be
+ * contacted at [email protected] (for great email, take off every 'zig').
+ * Porting to Java was done by Thomas Hodge, who may be contacted at
+ * [email protected] (remove every 'zag').
+ *
+ * libnoiseforjava is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * libnoiseforjava is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * libnoiseforjava. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package libnoiseforjava.module;
+
+import libnoiseforjava.exception.ExceptionInvalidParam;
+
+public class Clamp extends ModuleBase
+{
+
+ /// Noise module that clamps the output value from a source module to a
+ /// range of values.
+ ///
+ /// @image html moduleclamp.png
+ ///
+ /// The range of values in which to clamp the output value is called the
+ /// <i>clamping range</i>.
+ ///
+ /// If the output value from the source module is less than the lower
+ /// bound of the clamping range, this noise module clamps that value to
+ /// the lower bound. If the output value from the source module is
+ /// greater than the upper bound of the clamping range, this noise module
+ /// clamps that value to the upper bound.
+ ///
+ /// To specify the upper and lower bounds of the clamping range, call the
+ /// setBounds() method.
+ ///
+ /// This noise module requires one source module.
+
+ /// Default lower bound of the clamping range for the Clamp noise module.
+ static final double DEFAULT_CLAMP_LOWER_BOUND = -1.0;
+
+ /// Default upper bound of the clamping range for the Clamp noise module.
+ static final double DEFAULT_CLAMP_UPPER_BOUND = 1.0;
+
+ double lowerBound, upperBound;
+
+ public Clamp (ModuleBase sourceModule) throws ExceptionInvalidParam
+ {
+ super(1);
+ setSourceModule(0, sourceModule);
+
+ lowerBound = DEFAULT_CLAMP_LOWER_BOUND;
+ upperBound = DEFAULT_CLAMP_UPPER_BOUND;
+ }
+
+ public double getValue (double x, double y, double z)
+ {
+ assert (sourceModules[0] != null);
+
+ double value = sourceModules[0].getValue (x, y, z);
+ if (value < lowerBound)
+ return lowerBound;
+ else if (value > upperBound)
+ return upperBound;
+ else
+ return value;
+ }
+
+ public void setBounds (double lowerBound, double upperBound)
+ {
+ assert (lowerBound < upperBound);
+
+ this.lowerBound = lowerBound;
+ this.upperBound = upperBound;
+ }
+
+}
diff --git a/src/libnoiseforjava/module/Const.java b/src/libnoiseforjava/module/Const.java new file mode 100644 index 0000000..4454f7d --- /dev/null +++ b/src/libnoiseforjava/module/Const.java @@ -0,0 +1,70 @@ +/*
+ * Copyright (C) 2003, 2004 Jason Bevins (original libnoise code)
+ * Copyright 2010 Thomas J. Hodge (java port of libnoise)
+ *
+ * This file is part of libnoiseforjava.
+ *
+ * libnoiseforjava is a Java port of the C++ library libnoise, which may be found at
+ * http://libnoise.sourceforge.net/. libnoise was developed by Jason Bevins, who may be
+ * contacted at [email protected] (for great email, take off every 'zig').
+ * Porting to Java was done by Thomas Hodge, who may be contacted at
+ * [email protected] (remove every 'zag').
+ *
+ * libnoiseforjava is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * libnoiseforjava is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * libnoiseforjava. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package libnoiseforjava.module;
+
+public class Const extends ModuleBase
+{
+ /// Noise module that outputs a constant value.
+ ///
+ /// @image html moduleconst.png
+ ///
+ /// To specify the constant value, call the setConstValue() method.
+ ///
+ /// This noise module is not useful by itself, but it is often used as a
+ /// source module for other noise modules.
+ ///
+ /// This noise module does not require any source modules.
+
+ /// Default constant value for the Const noise module.
+ static final double DEFAULT_CONST_VALUE = 0.0;
+
+ double constValue;
+
+ public Const ()
+ {
+ super(0);
+ this.constValue = DEFAULT_CONST_VALUE;
+ }
+
+ public Const(double c) {
+ super(0);
+ this.constValue = c;
+ }
+
+ public double getValue (double x, double y, double z)
+ {
+ return constValue;
+ }
+
+ /// Sets the constant output value for this noise module.
+ ///
+ /// @param constValue The constant output value for this noise module.
+ public void setConstValue (double constValue)
+ {
+ this.constValue = constValue;
+ }
+
+}
diff --git a/src/libnoiseforjava/module/Curve.java b/src/libnoiseforjava/module/Curve.java new file mode 100644 index 0000000..2d78818 --- /dev/null +++ b/src/libnoiseforjava/module/Curve.java @@ -0,0 +1,203 @@ +/*
+ * Copyright (C) 2003, 2004 Jason Bevins (original libnoise code)
+ * Copyright 2010 Thomas J. Hodge (java port of libnoise)
+ *
+ * This file is part of libnoiseforjava.
+ *
+ * libnoiseforjava is a Java port of the C++ library libnoise, which may be found at
+ * http://libnoise.sourceforge.net/. libnoise was developed by Jason Bevins, who may be
+ * contacted at [email protected] (for great email, take off every 'zig').
+ * Porting to Java was done by Thomas Hodge, who may be contacted at
+ * [email protected] (remove every 'zag').
+ *
+ * libnoiseforjava is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * libnoiseforjava is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * libnoiseforjava. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package libnoiseforjava.module;
+
+import libnoiseforjava.Interp;
+import libnoiseforjava.Misc;
+import libnoiseforjava.exception.ExceptionInvalidParam;
+
+public class Curve extends ModuleBase
+{
+ /// Noise module that maps the output value from a source module onto an
+ /// arbitrary function curve.
+ ///
+ /// This noise module maps the output value from the source module onto an
+ /// application-defined curve. This curve is defined by a number of
+ /// <i>control points</i>; each control point has an <i>input value</i>
+ /// that maps to an <i>output value</i>.
+ ///
+ /// To add the control points to this curve, call the addControlPoint()
+ /// method. Note that the class ControlPoint follows the class Curve in
+ /// this file.
+ ///
+ /// Since this curve is a cubic spline, an application must add a minimum
+ /// of four control points to the curve. If this is not done, the
+ /// getValue() method fails. Each control point can have any input and
+ /// output value, although no two control points can have the same input
+ /// value. There is no limit to the number of control points that can be
+ /// added to the curve.
+ ///
+ /// This noise module requires one source module
+
+ int controlPointCount;
+ ControlPoint[] controlPoints;
+
+ public Curve (ModuleBase sourceModule) throws ExceptionInvalidParam
+ {
+ super(1);
+ setSourceModule(0, sourceModule);
+ controlPointCount = 0;
+ controlPoints= new ControlPoint[1];
+ controlPoints[0] = new ControlPoint(0.0, 0.0);
+ }
+
+ public void addControlPoint (double inputValue, double outputValue)
+ throws ExceptionInvalidParam
+ {
+ // Find the insertion point for the new control point and insert the new
+ // point at that position. The control point array will remain sorted by
+ // input value.
+ int insertionPos = findInsertionPos(inputValue);
+ insertAtPos (insertionPos, inputValue, outputValue);
+ }
+
+ public void clearAllControlPoints ()
+ {
+ controlPoints = null;
+ controlPointCount = 0;
+ }
+
+ public int findInsertionPos (double inputValue) throws ExceptionInvalidParam
+ {
+ int insertionPos;
+ for (insertionPos = 0; insertionPos < controlPointCount; insertionPos++)
+ {
+ if (inputValue < controlPoints[insertionPos].inputValue)
+ // We found the array index in which to insert the new control point.
+ // Exit now.
+ break;
+ else if (inputValue == controlPoints[insertionPos].inputValue)
+ // Each control point is required to contain a unique input value, so
+ // throw an exception.
+ throw new ExceptionInvalidParam("Invalid Parameter in Curve");
+ }
+ return insertionPos;
+ }
+
+ public double getValue (double x, double y, double z)
+ {
+ assert (sourceModules[0] != null);
+ assert (controlPointCount >= 4);
+
+ // Get the output value from the source module.
+ double sourceModuleValue = sourceModules[0].getValue (x, y, z);
+
+ // Find the first element in the control point array that has an input value
+ // larger than the output value from the source module.
+ int indexPos;
+ for (indexPos = 0; indexPos < controlPointCount; indexPos++)
+ {
+ if (sourceModuleValue < controlPoints[indexPos].inputValue)
+ break;
+
+ }
+
+ // Find the four nearest control points so that we can perform cubic
+ // interpolation.
+ int index0 = Misc.ClampValue (indexPos - 2, 0, controlPointCount - 1);
+ int index1 = Misc.ClampValue (indexPos - 1, 0, controlPointCount - 1);
+ int index2 = Misc.ClampValue (indexPos , 0, controlPointCount - 1);
+ int index3 = Misc.ClampValue (indexPos + 1, 0, controlPointCount - 1);
+
+ // If some control points are missing (which occurs if the value from the
+ // source module is greater than the largest input value or less than the
+ // smallest input value of the control point array), get the corresponding
+ // output value of the nearest control point and exit now.
+ if (index1 == index2) {
+ return controlPoints[index1].outputValue;
+ }
+
+ // Compute the alpha value used for cubic interpolation.
+ double input0 = controlPoints[index1].inputValue;
+ double input1 = controlPoints[index2].inputValue;
+ double alpha = (sourceModuleValue - input0) / (input1 - input0);
+
+ // Now perform the cubic interpolation given the alpha value.
+ return Interp.cubicInterp(
+ controlPoints[index0].outputValue,
+ controlPoints[index1].outputValue,
+ controlPoints[index2].outputValue,
+ controlPoints[index3].outputValue,
+ alpha);
+ }
+
+ public void insertAtPos (int insertionPos, double inputValue,
+ double outputValue)
+ {
+ // Make room for the new control point at the specified position within the
+ // control point array. The position is determined by the input value of
+ // the control point; the control points must be sorted by input value
+ // within that array.
+ ControlPoint[] newControlPoints = new ControlPoint[controlPointCount + 1];
+
+ for (int t = 0; t < (controlPointCount + 1); t++)
+ newControlPoints[t] = new ControlPoint();
+
+ for (int i = 0; i < controlPointCount; i++) {
+ if (i < insertionPos) {
+ newControlPoints[i] = controlPoints[i];
+ } else {
+ newControlPoints[i + 1] = controlPoints[i];
+ }
+ }
+
+ controlPoints = newControlPoints;
+ ++controlPointCount;
+
+ // Now that we've made room for the new control point within the array, add
+ // the new control point.
+ controlPoints[insertionPos].inputValue = inputValue;
+ controlPoints[insertionPos].outputValue = outputValue;
+ }
+}
+
+
+/// This class defines a control point.
+///
+/// Control points are used for defining splines.
+class ControlPoint
+{
+ /// The input value.
+ double inputValue;
+
+ /// The output value that is mapped from the input value.
+ double outputValue;
+
+ ControlPoint()
+ {
+ inputValue = 0.0;
+ outputValue = 0.0;
+ }
+
+ ControlPoint(double inputValue, double outputValue)
+ {
+ this.inputValue = inputValue;
+ this.outputValue = outputValue;
+ }
+
+
+
+}
\ No newline at end of file diff --git a/src/libnoiseforjava/module/Cylinders.java b/src/libnoiseforjava/module/Cylinders.java new file mode 100644 index 0000000..c67d019 --- /dev/null +++ b/src/libnoiseforjava/module/Cylinders.java @@ -0,0 +1,103 @@ +/*
+ * Copyright (C) 2003, 2004 Jason Bevins (original libnoise code)
+ * Copyright 2010 Thomas J. Hodge (java port of libnoise)
+ *
+ * This file is part of libnoiseforjava.
+ *
+ * libnoiseforjava is a Java port of the C++ library libnoise, which may be found at
+ * http://libnoise.sourceforge.net/. libnoise was developed by Jason Bevins, who may be
+ * contacted at [email protected] (for great email, take off every 'zig').
+ * Porting to Java was done by Thomas Hodge, who may be contacted at
+ * [email protected] (remove every 'zag').
+ *
+ * libnoiseforjava is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * libnoiseforjava is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * libnoiseforjava. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package libnoiseforjava.module;
+
+public class Cylinders extends ModuleBase
+{
+ /// Noise module that outputs concentric cylinders.
+ ///
+ /// This noise module outputs concentric cylinders centered on the origin.
+ /// These cylinders are oriented along the @a y axis similar to the
+ /// concentric rings of a tree. Each cylinder extends infinitely along
+ /// the @a y axis.
+ ///
+ /// The first cylinder has a radius of 1.0. Each subsequent cylinder has
+ /// a radius that is 1.0 unit larger than the previous cylinder.
+ ///
+ /// The output value from this noise module is determined by the distance
+ /// between the input value and the the nearest cylinder surface. The
+ /// input values that are located on a cylinder surface are given the
+ /// output value 1.0 and the input values that are equidistant from two
+ /// cylinder surfaces are given the output value -1.0.
+ ///
+ /// An application can change the frequency of the concentric cylinders.
+ /// Increasing the frequency reduces the distances between cylinders. To
+ /// specify the frequency, call the setFrequency() method.
+ ///
+ /// This noise module, modified with some low-frequency, low-power
+ /// turbulence, is useful for generating wood-like textures.
+ ///
+ /// This noise module does not require any source modules.
+
+ /// Default frequency value for the Cylinders noise module.
+ static final double DEFAULT_CYLINDERS_FREQUENCY = 1.0;
+
+ /// Frequency of the concentric cylinders.
+ double frequency;
+
+ public Cylinders ()
+ {
+ super(0);
+ frequency = DEFAULT_CYLINDERS_FREQUENCY;
+ }
+
+ public double getValue (double x, double y, double z)
+ {
+ x *= frequency;
+ z *= frequency;
+
+ double distFromCenter = Math.sqrt(x * x + z * z);
+ double distFromSmallerSphere = distFromCenter - Math.floor(distFromCenter);
+ double distFromLargerSphere = 1.0 - distFromSmallerSphere;
+ double nearestDist = Math.min(distFromSmallerSphere, distFromLargerSphere);
+
+ // Puts it in the -1.0 to +1.0 range.
+ return 1.0 - (nearestDist * 4.0);
+ }
+
+ /// Returns the frequency of the concentric cylinders.
+ ///
+ /// @returns The frequency of the concentric cylinders.
+ ///
+ /// Increasing the frequency increases the density of the concentric
+ /// cylinders, reducing the distances between them.
+ public double getFrequency()
+ {
+ return frequency;
+ }
+
+ /// Sets the frequency of the concentric cylinders.
+ ///
+ /// @param frequency The frequency of the concentric cylinders.
+ ///
+ /// Increasing the frequency increases the density of the concentric
+ /// cylinders, reducing the distances between them.
+ public void setFrequency (double frequency)
+ {
+ this.frequency = frequency;
+ }
+
+}
diff --git a/src/libnoiseforjava/module/Displace.java b/src/libnoiseforjava/module/Displace.java new file mode 100644 index 0000000..7725ce6 --- /dev/null +++ b/src/libnoiseforjava/module/Displace.java @@ -0,0 +1,238 @@ +/*
+ * Copyright (C) 2003, 2004 Jason Bevins (original libnoise code)
+ * Copyright 2010 Thomas J. Hodge (java port of libnoise)
+ *
+ * This file is part of libnoiseforjava.
+ *
+ * libnoiseforjava is a Java port of the C++ library libnoise, which may be found at
+ * http://libnoise.sourceforge.net/. libnoise was developed by Jason Bevins, who may be
+ * contacted at [email protected] (for great email, take off every 'zig').
+ * Porting to Java was done by Thomas Hodge, who may be contacted at
+ * [email protected] (remove every 'zag').
+ *
+ * libnoiseforjava is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * libnoiseforjava is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * libnoiseforjava. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package libnoiseforjava.module;
+
+import libnoiseforjava.exception.ExceptionInvalidParam;
+import libnoiseforjava.exception.ExceptionNoModule;
+
+public class Displace extends ModuleBase
+{
+ /// Noise module that uses three source modules to displace each
+ /// coordinate of the input value before returning the output value from
+ /// a source module.
+ ///
+ /// Unlike most other noise modules, the index value assigned to a source
+ /// module determines its role in the displacement operation:
+ /// - Source module 0 (left in the diagram) outputs a value.
+ /// - Source module 1 (lower left in the diagram) specifies the offset to
+ /// apply to the @a x coordinate of the input value.
+ /// - Source module 2 (lower center in the diagram) specifies the
+ /// offset to apply to the @a y coordinate of the input value.
+ /// - Source module 3 (lower right in the diagram) specifies the offset
+ /// to apply to the @a z coordinate of the input value.
+ ///
+ /// The getValue() method modifies the ( @a x, @a y, @a z ) coordinates of
+ /// the input value using the output values from the three displacement
+ /// modules before retrieving the output value from the source module.
+ ///
+ /// The Turbulence noise module is a special case of the
+ /// Displace module; internally, there are three Perlin-noise modules
+ /// that perform the displacement operation.
+ ///
+ /// This noise module requires four source modules.
+
+ public Displace (ModuleBase sourceModuleOne, ModuleBase sourceModuleTwo,
+ ModuleBase sourceModuleThree, ModuleBase sourceModuleFour) throws ExceptionInvalidParam
+ {
+ super(4);
+ setSourceModule(0, sourceModuleOne);
+ setSourceModule(1, sourceModuleTwo);
+ setSourceModule(2, sourceModuleThree);
+ setSourceModule(3, sourceModuleFour);
+ }
+
+ public double getValue (double x, double y, double z)
+ {
+ assert (sourceModules[0] != null);
+ assert (sourceModules[1] != null);
+ assert (sourceModules[2] != null);
+ assert (sourceModules[3] != null);
+
+ // Get the output values from the three displacement modules. Add each
+ // value to the corresponding coordinate in the input value.
+ double xDisplace = x + (sourceModules[1].getValue (x, y, z));
+ double yDisplace = y + (sourceModules[2].getValue (x, y, z));
+ double zDisplace = z + (sourceModules[3].getValue (x, y, z));
+
+ // Retrieve the output value using the offset input value instead of
+ // the original input value.
+ return sourceModules[0].getValue (xDisplace, yDisplace, zDisplace);
+ }
+
+ public ModuleBase getXDisplaceModule() throws ExceptionNoModule
+ {
+ if (sourceModules == null || sourceModules[1] == null)
+ throw new ExceptionNoModule ("Could not retrieve a source module " +
+ "from a noise module.");
+
+ return sourceModules[1];
+ }
+
+ /// Returns the @a y displacement module.
+ ///
+ /// @returns A reference to the @a y displacement module.
+ ///
+ /// @pre This displacement module has been added to this noise module
+ /// via a call to setSourceModule() or setYDisplaceModule().
+ ///
+ /// @throw ExceptionNoModule See the preconditions for more
+ /// information.
+ ///
+ /// The getValue() method displaces the input value by adding the output
+ /// value from this displacement module to the @a y coordinate of the
+ /// input value before returning the output value from the source
+ /// module.
+ public ModuleBase getYDisplaceModule () throws ExceptionNoModule
+ {
+ if (sourceModules == null || sourceModules[2] == null)
+ throw new ExceptionNoModule ("Could not retrieve a source module " +
+ "from Displace noise module.");
+
+ return sourceModules[2];
+ }
+
+ /// Returns the @a z displacement module.
+ ///
+ /// @returns A reference to the @a z displacement module.
+ ///
+ /// @pre This displacement module has been added to this noise module
+ /// via a call to setSourceModule() or setZDisplaceModule().
+ ///
+ /// @throw ExceptionNoModule See the preconditions for more
+ /// information.
+ ///
+ /// The getValue() method displaces the input value by adding the output
+ /// value from this displacement module to the @a z coordinate of the
+ /// input value before returning the output value from the source
+ /// module.
+ public ModuleBase getZDisplaceModule () throws ExceptionNoModule
+ {
+ if (sourceModules == null || sourceModules[3] == null)
+ throw new ExceptionNoModule ("Could not retrieve a source module " +
+ "from Displace noise module.");
+
+ return sourceModules[3];
+ }
+
+
+ /// Sets the @a x, @a y, and @a z displacement modules.
+ ///
+ /// @param xDisplaceModule Displacement module that displaces the @a x
+ /// coordinate of the input value.
+ /// @param yDisplaceModule Displacement module that displaces the @a y
+ /// coordinate of the input value.
+ /// @param zDisplaceModule Displacement module that displaces the @a z
+ /// coordinate of the input value.
+ ///
+ /// The getValue() method displaces the input value by adding the output
+ /// value from each of the displacement modules to the corresponding
+ /// coordinates of the input value before returning the output value
+ /// from the source module.
+ ///
+ /// This method assigns an index value of 1 to the @a x displacement
+ /// module, an index value of 2 to the @a y displacement module, and an
+ /// index value of 3 to the @a z displacement module.
+ ///
+ /// These displacement modules must exist throughout the lifetime of
+ /// this noise module unless another displacement module replaces it.
+ public void setDisplaceModules (ModuleBase xDisplaceModule,
+ ModuleBase yDisplaceModule, ModuleBase zDisplaceModule)
+ {
+ setXDisplaceModule (xDisplaceModule);
+ setYDisplaceModule (yDisplaceModule);
+ setZDisplaceModule (zDisplaceModule);
+ }
+
+ /// Sets the @a x displacement module.
+ ///
+ /// @param xDisplaceModule Displacement module that displaces the @a x
+ /// coordinate.
+ ///
+ /// The getValue() method displaces the input value by adding the output
+ /// value from this displacement module to the @a x coordinate of the
+ /// input value before returning the output value from the source
+ /// module.
+ ///
+ /// This method assigns an index value of 1 to the @a x displacement
+ /// module. Passing this displacement module to this method produces
+ /// the same results as passing this displacement module to the
+ /// setSourceModule() method while assigning it an index value of 1.
+ ///
+ /// This displacement module must exist throughout the lifetime of this
+ /// noise module unless another displacement module replaces it.
+ public void setXDisplaceModule (ModuleBase xDisplaceModule)
+ {
+ assert (sourceModules != null);
+ sourceModules[1] = xDisplaceModule;
+ }
+
+ /// Sets the @a y displacement module.
+ ///
+ /// @param yDisplaceModule Displacement module that displaces the @a y
+ /// coordinate.
+ ///
+ /// The getValue() method displaces the input value by adding the output
+ /// value from this displacement module to the @a y coordinate of the
+ /// input value before returning the output value from the source
+ /// module.
+ ///
+ /// This method assigns an index value of 2 to the @a y displacement
+ /// module. Passing this displacement module to this method produces
+ /// the same results as passing this displacement module to the
+ /// setSourceModule() method while assigning it an index value of 2.
+ ///
+ /// This displacement module must exist throughout the lifetime of this
+ /// noise module unless another displacement module replaces it.
+ public void setYDisplaceModule (ModuleBase yDisplaceModule)
+ {
+ assert (sourceModules != null);
+ sourceModules[2] = yDisplaceModule;
+ }
+
+ /// Sets the @a z displacement module.
+ ///
+ /// @param zDisplaceModule Displacement module that displaces the @a z
+ /// coordinate.
+ ///
+ /// The getValue() method displaces the input value by adding the output
+ /// value from this displacement module to the @a z coordinate of the
+ /// input value before returning the output value from the source
+ /// module.
+ ///
+ /// This method assigns an index value of 3 to the @a z displacement
+ /// module. Passing this displacement module to this method produces
+ /// the same results as passing this displacement module to the
+ /// setSourceModule() method while assigning it an index value of 3.
+ ///
+ /// This displacement module must exist throughout the lifetime of this
+ /// noise module unless another displacement module replaces it.
+ public void setZDisplaceModule (ModuleBase zDisplaceModule)
+ {
+ assert (sourceModules != null);
+ sourceModules[3] = zDisplaceModule;
+ }
+
+}
diff --git a/src/libnoiseforjava/module/Exponent.java b/src/libnoiseforjava/module/Exponent.java new file mode 100644 index 0000000..64f9cdc --- /dev/null +++ b/src/libnoiseforjava/module/Exponent.java @@ -0,0 +1,79 @@ +/*
+ * Copyright (C) 2003, 2004 Jason Bevins (original libnoise code)
+ * Copyright 2010 Thomas J. Hodge (java port of libnoise)
+ *
+ * This file is part of libnoiseforjava.
+ *
+ * libnoiseforjava is a Java port of the C++ library libnoise, which may be found at
+ * http://libnoise.sourceforge.net/. libnoise was developed by Jason Bevins, who may be
+ * contacted at [email protected] (for great email, take off every 'zig').
+ * Porting to Java was done by Thomas Hodge, who may be contacted at
+ * [email protected] (remove every 'zag').
+ *
+ * libnoiseforjava is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * libnoiseforjava is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * libnoiseforjava. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package libnoiseforjava.module;
+
+import libnoiseforjava.exception.ExceptionInvalidParam;
+
+public class Exponent extends ModuleBase
+{
+ /// Noise module that maps the output value from a source module onto an
+ /// exponential curve.
+ ///
+ /// Because most noise modules will output values that range from -1.0 to
+ /// +1.0, this noise module first normalizes this output value (the range
+ /// becomes 0.0 to 1.0), maps that value onto an exponential curve, then
+ /// rescales that value back to the original range.
+ ///
+ /// This noise module requires one source module.
+
+ /// Default exponent for the Exponent noise module.
+ static final double DEFAULT_EXPONENT = 1.0;
+
+
+ /// Exponent to apply to the output value from the source module.
+ double exponent;
+
+ public Exponent (ModuleBase sourceModule) throws ExceptionInvalidParam
+ {
+ super(1);
+ setSourceModule(0, sourceModule);
+ exponent = DEFAULT_EXPONENT;
+
+ }
+
+ public double getValue (double x, double y, double z)
+ {
+ assert (sourceModules[0] != null);
+
+ double value = sourceModules[0].getValue (x, y, z);
+ return (Math.pow (Math.abs ((value + 1.0) / 2.0), exponent) * 2.0 - 1.0);
+ }
+
+ /// Returns the exponent value to apply to the output value from the
+ /// source module.
+ ///
+ /// @returns The exponent value.
+ public double getExponent ()
+ {
+ return exponent;
+ }
+
+ public void setExponent(double exponent)
+ {
+ this.exponent = exponent;
+ }
+
+}
diff --git a/src/libnoiseforjava/module/Gradient.java b/src/libnoiseforjava/module/Gradient.java new file mode 100644 index 0000000..91b4132 --- /dev/null +++ b/src/libnoiseforjava/module/Gradient.java @@ -0,0 +1,119 @@ +/*
+ * Copyright (C) 2003, 2004 Jason Bevins (original libnoise code)
+ * Copyright 2010 Thomas J. Hodge (java port of libnoise)
+ * Copyright 2012 Michael Nugent (This module)
+ *
+ * This file is part of libnoiseforjava.
+ *
+ * libnoiseforjava is a Java port of the C++ library libnoise, which may be found at
+ * http://libnoise.sourceforge.net/. libnoise was developed by Jason Bevins, who may be
+ * contacted at [email protected] (for great email, take off every 'zig').
+ * Porting to Java was done by Thomas Hodge, who may be contacted at
+ * [email protected] (remove every 'zag').
+ *
+ * libnoiseforjava is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * libnoiseforjava is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * libnoiseforjava. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package libnoiseforjava.module;
+
+/**
+ * User: mike nugent
+ * Date: 2/5/12
+ * Time: 4:40 PM
+ * URL: https://github.com/michaelnugent/libnoiseforjava
+ * Package: libnoiseforjava.module
+ */
+public class Gradient extends ModuleBase {
+
+ AXIS axis = AXIS.Y;
+
+ double inputMin = 0;
+ double inputMax = 255;
+
+ double scaledMin = -1;
+ double scaledMax = 1;
+
+ public enum AXIS {
+ X,
+ Y,
+ Z
+ };
+
+ public Gradient() {
+ super();
+ }
+
+ public Gradient(AXIS axis) {
+ super();
+ this.axis = axis;
+ }
+
+ public double getValue(double x, double y, double z) {
+ if (axis == AXIS.Y) {
+ double outy = scale(y, this.inputMin, this.inputMax, this.scaledMin, this.scaledMax);
+ return outy;
+ } else if (axis == AXIS.X) {
+ double outx = scale(x, this.inputMin, this.inputMax, this.scaledMin, this.scaledMax);
+ return outx;
+ } else {
+ double outz = scale(z, this.inputMin, this.inputMax, this.scaledMin, this.scaledMax);
+ return outz;
+ }
+ }
+
+ private double scale( double inVal, double inMin, double inMax, double min, double max ) {
+ double m = (max-min)/(inMax-inMin);
+ double c = min-inMin*m;
+ return m*inVal+c;
+ }
+
+ public AXIS getAxis() {
+ return axis;
+ }
+
+ public void setAxis(AXIS axis) {
+ this.axis = axis;
+ }
+
+ public double getInputMin() {
+ return inputMin;
+ }
+
+ public void setInputMin(double inputMin) {
+ this.inputMin = inputMin;
+ }
+
+ public double getInputMax() {
+ return inputMax;
+ }
+
+ public void setInputMax(double inputMax) {
+ this.inputMax = inputMax;
+ }
+
+ public double getScaledMin() {
+ return scaledMin;
+ }
+
+ public void setScaledMin(double scaledMin) {
+ this.scaledMin = scaledMin;
+ }
+
+ public double getScaledMax() {
+ return scaledMax;
+ }
+
+ public void setScaledMax(double scaledMax) {
+ this.scaledMax = scaledMax;
+ }
+}
diff --git a/src/libnoiseforjava/module/Identity.java b/src/libnoiseforjava/module/Identity.java new file mode 100644 index 0000000..6fe0f3a --- /dev/null +++ b/src/libnoiseforjava/module/Identity.java @@ -0,0 +1,70 @@ +/*
+ * Copyright (C) 2003, 2004 Jason Bevins (original libnoise code)
+ * Copyright 2010 Thomas J. Hodge (java port of libnoise)
+ * Copyright 2012 Michael Nugent (This module)
+ *
+ * This file is part of libnoiseforjava.
+ *
+ * libnoiseforjava is a Java port of the C++ library libnoise, which may be found at
+ * http://libnoise.sourceforge.net/. libnoise was developed by Jason Bevins, who may be
+ * contacted at [email protected] (for great email, take off every 'zig').
+ * Porting to Java was done by Thomas Hodge, who may be contacted at
+ * [email protected] (remove every 'zag').
+ *
+ * libnoiseforjava is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * libnoiseforjava is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * libnoiseforjava. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package libnoiseforjava.module;
+
+/**
+ * User: mike nugent
+ * Date: 2/5/12
+ * Time: 4:19 PM
+ * URL: https://github.com/michaelnugent/libnoiseforjava
+ * Package: libnoiseforjava.module
+ */
+public class Identity extends ModuleBase {
+
+ AXIS axis = AXIS.Y;
+
+ public enum AXIS {
+ X,
+ Y,
+ Z
+ };
+
+ public Identity() {
+ super();
+ }
+
+ public Identity( AXIS axis ) {
+ super();
+ this.axis = axis;
+ }
+
+ public void setAxis( AXIS axis ) {
+ this.axis = axis;
+ }
+
+ public double getValue(double x, double y, double z) {
+ if ( axis == AXIS.Y ) {
+ return y;
+ }
+ else if ( axis == AXIS.X ) {
+ return x;
+ }
+ else {
+ return z;
+ }
+ }
+}
diff --git a/src/libnoiseforjava/module/Intersection.java b/src/libnoiseforjava/module/Intersection.java new file mode 100644 index 0000000..4a0f20e --- /dev/null +++ b/src/libnoiseforjava/module/Intersection.java @@ -0,0 +1,63 @@ +/*
+ * Copyright (C) 2003, 2004 Jason Bevins (original libnoise code)
+ * Copyright 2010 Thomas J. Hodge (java port of libnoise)
+ * Copyright 2012 Michael Nugent (This module)
+ *
+ * This file is part of libnoiseforjava.
+ *
+ * libnoiseforjava is a Java port of the C++ library libnoise, which may be found at
+ * http://libnoise.sourceforge.net/. libnoise was developed by Jason Bevins, who may be
+ * contacted at [email protected] (for great email, take off every 'zig').
+ * Porting to Java was done by Thomas Hodge, who may be contacted at
+ * [email protected] (remove every 'zag').
+ *
+ * libnoiseforjava is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * libnoiseforjava is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * libnoiseforjava. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package libnoiseforjava.module;
+
+import libnoiseforjava.exception.ExceptionInvalidParam;
+
+/**
+ * User: mike nugent
+ * Date: 2/18/12
+ * Time: 11:57 PM
+ * URL: https://github.com/michaelnugent/libnoiseforjava
+ * Package: libnoiseforjava.module
+ */
+public class Intersection extends ModuleBase {
+ double cutoff;
+ public Intersection(ModuleBase sourceModuleOne, ModuleBase sourceModuleTwo, double cutoff) throws ExceptionInvalidParam
+ {
+ super(2);
+ setSourceModule(0, sourceModuleOne);
+ setSourceModule(1, sourceModuleTwo);
+ this.cutoff = cutoff;
+ }
+
+ public double getValue (double x, double y, double z)
+ {
+ assert (sourceModules[0] != null);
+ assert (sourceModules[1] != null);
+
+ double s1 = sourceModules[0].getValue(x,y,z);
+ double s2 = sourceModules[1].getValue(x,y,z);
+
+ if ( s1 + cutoff > s2 && s1 - cutoff < s2 ) {
+ return s1;
+ }
+ else {
+ return -1;
+ }
+ }
+}
diff --git a/src/libnoiseforjava/module/Invert.java b/src/libnoiseforjava/module/Invert.java new file mode 100644 index 0000000..106b79f --- /dev/null +++ b/src/libnoiseforjava/module/Invert.java @@ -0,0 +1,48 @@ +/*
+ * Copyright (C) 2003, 2004 Jason Bevins (original libnoise code)
+ * Copyright 2010 Thomas J. Hodge (java port of libnoise)
+ *
+ * This file is part of libnoiseforjava.
+ *
+ * libnoiseforjava is a Java port of the C++ library libnoise, which may be found at
+ * http://libnoise.sourceforge.net/. libnoise was developed by Jason Bevins, who may be
+ * contacted at [email protected] (for great email, take off every 'zig').
+ * Porting to Java was done by Thomas Hodge, who may be contacted at
+ * [email protected] (remove every 'zag').
+ *
+ * libnoiseforjava is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * libnoiseforjava is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * libnoiseforjava. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package libnoiseforjava.module;
+
+import libnoiseforjava.exception.ExceptionInvalidParam;
+
+public class Invert extends ModuleBase
+{
+ /// Noise module that inverts the output value from a source module.
+ ///
+ /// This noise module requires one source module.
+ public Invert (ModuleBase sourceModule) throws ExceptionInvalidParam
+ {
+ super(1);
+ setSourceModule(0, sourceModule);
+ }
+
+ public double getValue (double x, double y, double z)
+ {
+ assert (sourceModules[0] != null);
+
+ return -(sourceModules[0].getValue (x, y, z));
+ }
+
+}
diff --git a/src/libnoiseforjava/module/Max.java b/src/libnoiseforjava/module/Max.java new file mode 100644 index 0000000..34757f6 --- /dev/null +++ b/src/libnoiseforjava/module/Max.java @@ -0,0 +1,54 @@ +/*
+ * Copyright (C) 2003, 2004 Jason Bevins (original libnoise code)
+ * Copyright 2010 Thomas J. Hodge (java port of libnoise)
+ *
+ * This file is part of libnoiseforjava.
+ *
+ * libnoiseforjava is a Java port of the C++ library libnoise, which may be found at
+ * http://libnoise.sourceforge.net/. libnoise was developed by Jason Bevins, who may be
+ * contacted at [email protected] (for great email, take off every 'zig').
+ * Porting to Java was done by Thomas Hodge, who may be contacted at
+ * [email protected] (remove every 'zag').
+ *
+ * libnoiseforjava is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * libnoiseforjava is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * libnoiseforjava. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package libnoiseforjava.module;
+
+import libnoiseforjava.exception.ExceptionInvalidParam;
+
+public class Max extends ModuleBase
+{
+ /// Noise module that outputs the larger of the two output values from two
+ /// source modules.
+ ///
+ /// This noise module requires two source modules.
+
+ public Max (ModuleBase sourceModuleOne, ModuleBase sourceModuleTwo) throws ExceptionInvalidParam
+ {
+ super(2);
+ setSourceModule(0, sourceModuleOne);
+ setSourceModule(1, sourceModuleTwo);
+ }
+
+ public double getValue (double x, double y, double z)
+ {
+ assert (sourceModules[0] != null);
+ assert (sourceModules[1] != null);
+
+ double v0 = sourceModules[0].getValue (x, y, z);
+ double v1 = sourceModules[1].getValue (x, y, z);
+ return Math.max(v0, v1);
+ }
+
+}
diff --git a/src/libnoiseforjava/module/Min.java b/src/libnoiseforjava/module/Min.java new file mode 100644 index 0000000..cd6bea0 --- /dev/null +++ b/src/libnoiseforjava/module/Min.java @@ -0,0 +1,56 @@ +/*
+ * Copyright (C) 2003, 2004 Jason Bevins (original libnoise code)
+ * Copyright 2010 Thomas J. Hodge (java port of libnoise)
+ *
+ * This file is part of libnoiseforjava.
+ *
+ * libnoiseforjava is a Java port of the C++ library libnoise, which may be found at
+ * http://libnoise.sourceforge.net/. libnoise was developed by Jason Bevins, who may be
+ * contacted at [email protected] (for great email, take off every 'zig').
+ * Porting to Java was done by Thomas Hodge, who may be contacted at
+ * [email protected] (remove every 'zag').
+ *
+ * libnoiseforjava is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * libnoiseforjava is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * libnoiseforjava. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package libnoiseforjava.module;
+
+import libnoiseforjava.exception.ExceptionInvalidParam;
+
+public class Min extends ModuleBase
+{
+ /// Noise module that outputs the smaller of the two output values from
+ /// two source modules.
+ ///
+ /// @image html modulemin.png
+ ///
+ /// This noise module requires two source modules.
+
+ public Min (ModuleBase sourceModuleOne, ModuleBase sourceModuleTwo) throws ExceptionInvalidParam
+ {
+ super(2);
+ setSourceModule(0, sourceModuleOne);
+ setSourceModule(1, sourceModuleTwo);
+ }
+
+ public double getValue (double x, double y, double z)
+ {
+ assert (sourceModules[0] != null);
+ assert (sourceModules[1] != null);
+
+ double v0 = sourceModules[0].getValue (x, y, z);
+ double v1 = sourceModules[1].getValue (x, y, z);
+ return Math.min(v0, v1);
+ }
+
+}
diff --git a/src/libnoiseforjava/module/ModuleBase.java b/src/libnoiseforjava/module/ModuleBase.java new file mode 100644 index 0000000..895e67b --- /dev/null +++ b/src/libnoiseforjava/module/ModuleBase.java @@ -0,0 +1,171 @@ +/*
+ * Copyright (C) 2003, 2004 Jason Bevins (original libnoise code)
+ * Copyright 2010 Thomas J. Hodge (java port of libnoise)
+ *
+ * This file is part of libnoiseforjava.
+ *
+ * libnoiseforjava is a Java port of the C++ library libnoise, which may be found at
+ * http://libnoise.sourceforge.net/. libnoise was developed by Jason Bevins, who may be
+ * contacted at [email protected] (for great email, take off every 'zig').
+ * Porting to Java was done by Thomas Hodge, who may be contacted at
+ * [email protected] (remove every 'zag').
+ *
+ * libnoiseforjava is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * libnoiseforjava is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * libnoiseforjava. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package libnoiseforjava.module;
+
+import libnoiseforjava.exception.ExceptionInvalidParam;
+import libnoiseforjava.exception.ExceptionNoModule;
+
+public class ModuleBase
+{
+
+ // base class for noise modules.
+ public ModuleBase[] sourceModules;
+ public int modulesRequired;
+
+ public ModuleBase()
+ {
+ modulesRequired = 0;
+ }
+
+ public ModuleBase (int modulesRequired)
+ {
+ // Create an array of pointers to all source modules required by this
+ // noise module. Set these pointers to null.
+ if(modulesRequired>0)
+ {
+ sourceModules = new ModuleBase[modulesRequired];
+ for (int i = 0; i < modulesRequired; i++)
+ {
+ sourceModules[i] = new ModuleBase();
+ }
+ }
+ else
+ sourceModules = null;
+
+ this.modulesRequired = modulesRequired;
+ }
+
+ /// Returns a reference to a source module connected to this noise
+ /// module.
+ ///
+ /// @param index The index value assigned to the source module.
+ ///
+ /// @returns A reference to the source module.
+ ///
+ /// @pre The index value ranges from 0 to one less than the number of
+ /// source modules required by this noise module.
+ /// @pre A source module with the specified index value has been added
+ /// to this noise module via a call to setSourceModule().
+ ///
+ /// @throw ExceptionNoModule See the preconditions for more
+ /// information.
+ ///
+ /// Each noise module requires the attachment of a certain number of
+ /// source modules before an application can call the getValue()
+ /// method.
+ public ModuleBase getSourceModule (int index) throws ExceptionNoModule
+ {
+ if (sourceModules != null)
+ {
+ if (index >= getSourceModuleCount () || index < 0
+ || sourceModules[index] == null)
+ {
+ throw new ExceptionNoModule ("Could not retrieve a source module " +
+ "from a noise module.");
+ }
+
+ return (sourceModules[index]);
+ }
+ throw new ExceptionNoModule ("Could not retrieve a source module " +
+ "from a noise module.");
+ }
+
+ /// Returns the number of source modules required by this noise
+ /// module.
+ ///
+ /// @returns The number of source modules required by this noise
+ /// module.
+ public int getSourceModuleCount()
+ {
+ return modulesRequired;
+ }
+
+ /// Generates an output value given the coordinates of the specified
+ /// input value.
+ ///
+ /// @param x The @a x coordinate of the input value.
+ /// @param y The @a y coordinate of the input value.
+ /// @param z The @a z coordinate of the input value.
+ ///
+ /// @returns The output value.
+ ///
+ /// @pre All source modules required by this noise module have been
+ /// passed to the setSourceModule() method.
+ ///
+ /// Before an application can call this method, it must first connect
+ /// all required source modules via the setSourceModule() method. If
+ /// these source modules are not connected to this noise module, this
+ /// method raises a debug assertion.
+ ///
+ /// To determine the number of source modules required by this noise
+ /// module, call the getSourceModuleCount() method.
+ public double getValue (double x, double y, double z)
+ {
+ return x;
+ }
+
+ /// Connects a source module to this noise module.
+ ///
+ /// @param index An index value to assign to this source module.
+ /// @param sourceModule The source module to attach.
+ ///
+ /// @pre The index value ranges from 0 to one less than the number of
+ /// source modules required by this noise module.
+ ///
+ /// @throw ExceptionInvalidParam An invalid parameter was
+ /// specified; see the preconditions for more information.
+ ///
+ /// A noise module mathematically combines the output values from the
+ /// source modules to generate the value returned by getValue().
+ ///
+ /// The index value to assign a source module is a unique identifier
+ /// for that source module. If an index value has already been
+ /// assigned to a source module, this noise module replaces the old
+ /// source module with the new source module.
+ ///
+ /// Before an application can call the getValue() method, it must
+ /// first connect all required source modules. To determine the
+ /// number of source modules required by this noise module, call the
+ /// getSourceModuleCount() method.
+ ///
+ /// This source module must exist throughout the lifetime of this
+ /// noise module unless another source module replaces that source
+ /// module.
+ ///
+ /// A noise module does not modify a source module; it only modifies
+ /// its output values.
+ public void setSourceModule (int index, ModuleBase sourceModule)
+ throws ExceptionInvalidParam
+ {
+ if (sourceModules != null)
+ {
+ if (index >= getSourceModuleCount () || index < 0)
+ throw new ExceptionInvalidParam ("Invalid Parameter in ModuleBase");
+ }
+ this.sourceModules[index] = sourceModule;
+ }
+
+}
diff --git a/src/libnoiseforjava/module/Multiply.java b/src/libnoiseforjava/module/Multiply.java new file mode 100644 index 0000000..944994e --- /dev/null +++ b/src/libnoiseforjava/module/Multiply.java @@ -0,0 +1,55 @@ +/*
+ * Copyright (C) 2003, 2004 Jason Bevins (original libnoise code)
+ * Copyright 2010 Thomas J. Hodge (java port of libnoise)
+ *
+ * This file is part of libnoiseforjava.
+ *
+ * libnoiseforjava is a Java port of the C++ library libnoise, which may be found at
+ * http://libnoise.sourceforge.net/. libnoise was developed by Jason Bevins, who may be
+ * contacted at [email protected] (for great email, take off every 'zig').
+ * Porting to Java was done by Thomas Hodge, who may be contacted at
+ * [email protected] (remove every 'zag').
+ *
+ * libnoiseforjava is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * libnoiseforjava is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * libnoiseforjava. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package libnoiseforjava.module;
+
+import libnoiseforjava.exception.ExceptionInvalidParam;
+
+public class Multiply extends ModuleBase
+{
+ /// Noise module that outputs the product of the two output values from
+ /// two source modules.
+ ///
+ /// @image html modulemultiply.png
+ ///
+ /// This noise module requires two source modules.
+
+ public Multiply (ModuleBase sourceModuleOne, ModuleBase sourceModuleTwo) throws ExceptionInvalidParam
+ {
+ super(2);
+ setSourceModule(0, sourceModuleOne);
+ setSourceModule(1, sourceModuleTwo);
+ }
+
+ public double getValue (double x, double y, double z)
+ {
+ assert (sourceModules[0] != null);
+ assert (sourceModules[1] != null);
+
+ return sourceModules[0].getValue (x, y, z)
+ * sourceModules[1].getValue (x, y, z);
+ }
+
+}
diff --git a/src/libnoiseforjava/module/Perlin.java b/src/libnoiseforjava/module/Perlin.java new file mode 100644 index 0000000..70fb22e --- /dev/null +++ b/src/libnoiseforjava/module/Perlin.java @@ -0,0 +1,357 @@ +/*
+ * Copyright (C) 2003, 2004 Jason Bevins (original libnoise code)
+ * Copyright 2010 Thomas J. Hodge (java port of libnoise)
+ *
+ * This file is part of libnoiseforjava.
+ *
+ * libnoiseforjava is a Java port of the C++ library libnoise, which may be found at
+ * http://libnoise.sourceforge.net/. libnoise was developed by Jason Bevins, who may be
+ * contacted at [email protected] (for great email, take off every 'zig').
+ * Porting to Java was done by Thomas Hodge, who may be contacted at
+ * [email protected] (remove every 'zag').
+ *
+ * libnoiseforjava is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * libnoiseforjava is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * libnoiseforjava. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package libnoiseforjava.module;
+
+import libnoiseforjava.NoiseGen;
+import libnoiseforjava.NoiseGen.NoiseQuality;
+import libnoiseforjava.exception.ExceptionInvalidParam;
+
+public class Perlin extends ModuleBase
+{
+ /// Noise module that outputs 3-dimensional Perlin noise.
+ ///
+ /// Perlin noise is the sum of several coherent-noise functions of
+ /// ever-increasing frequencies and ever-decreasing amplitudes.
+ ///
+ /// An important property of Perlin noise is that a small change in the
+ /// input value will produce a small change in the output value, while a
+ /// large change in the input value will produce a random change in the
+ /// output value.
+ ///
+ /// This noise module outputs Perlin-noise values that usually range from
+ /// -1.0 to +1.0, but there are no guarantees that all output values will
+ /// exist within that range.
+ ///
+ /// For a better description of Perlin noise, see the links in the
+ /// <i>References and Acknowledgments</i> section.
+ ///
+ /// This noise module does not require any source modules.
+ ///
+ /// <b>Octaves</b>
+ ///
+ /// The number of octaves control the <i>amount of detail</i> of the
+ /// Perlin noise. Adding more octaves increases the detail of the Perlin
+ /// noise, but with the drawback of increasing the calculation time.
+ ///
+ /// An octave is one of the coherent-noise functions in a series of
+ /// coherent-noise functions that are added together to form Perlin
+ /// noise.
+ ///
+ /// An application may specify the frequency of the first octave by
+ /// calling the setFrequency() method.
+ ///
+ /// An application may specify the number of octaves that generate Perlin
+ /// noise by calling the setOctaveCount() method.
+ ///
+ /// These coherent-noise functions are called octaves because each octave
+ /// has, by default, double the frequency of the previous octave. Musical
+ /// tones have this property as well; a musical C tone that is one octave
+ /// higher than the previous C tone has double its frequency.
+ ///
+ /// <b>Frequency</b>
+ ///
+ /// An application may specify the frequency of the first octave by
+ /// calling the setFrequency() method.
+ ///
+ /// <b>Persistence</b>
+ ///
+ /// The persistence value controls the <i>roughness</i> of the Perlin
+ /// noise. Larger values produce rougher noise.
+ ///
+ /// The persistence value determines how quickly the amplitudes diminish
+ /// for successive octaves. The amplitude of the first octave is 1.0.
+ /// The amplitude of each subsequent octave is equal to the product of the
+ /// previous octave's amplitude and the persistence value. So a
+ /// persistence value of 0.5 sets the amplitude of the first octave to
+ /// 1.0; the second, 0.5; the third, 0.25; etc.
+ ///
+ /// An application may specify the persistence value by calling the
+ /// setPersistence() method.
+ ///
+ /// <b>Lacunarity</b>
+ ///
+ /// The lacunarity specifies the frequency multipler between successive
+ /// octaves.
+ ///
+ /// The effect of modifying the lacunarity is subtle; you may need to play
+ /// with the lacunarity value to determine the effects. For best results,
+ /// set the lacunarity to a number between 1.5 and 3.5.
+ ///
+ /// <b>References & acknowledgments</b>
+ ///
+ /// <a href=http://www.noisemachine.com/talk1/>The Noise Machine</a> -
+ /// From the master, Ken Perlin himself. This page contains a
+ /// presentation that describes Perlin noise and some of its variants.
+ /// He won an Oscar for creating the Perlin noise algorithm!
+ ///
+ /// <a
+ /// href=http://freespace.virgin.net/hugo.elias/models/m_perlin.htm>
+ /// Perlin Noise</a> - Hugo Elias's webpage contains a very good
+ /// description of Perlin noise and describes its many applications. This
+ /// page gave me the inspiration to create libnoise in the first place.
+ /// Now that I know how to generate Perlin noise, I will never again use
+ /// cheesy subdivision algorithms to create terrain (unless I absolutely
+ /// need the speed.)
+ ///
+ /// <a
+ /// href=http://www.robo-murito.net/code/perlin-noise-math-faq.html>The
+ /// Perlin noise math FAQ</a> - A good page that describes Perlin noise in
+ /// plain English with only a minor amount of math. During development of
+ /// libnoise, I noticed that my coherent-noise function generated terrain
+ /// with some "regularity" to the terrain features. This page describes a
+ /// better coherent-noise function called <i>gradient noise</i>. This
+ /// version of the Perlin module uses gradient coherent noise to
+ /// generate Perlin noise.
+
+
+ /// Default frequency for the noise::module::Perlin noise module.
+ static final double DEFAULT_PERLIN_FREQUENCY = 1.0;
+
+ /// Default lacunarity for the noise::module::Perlin noise module.
+ static final double DEFAULT_PERLIN_LACUNARITY = 2.0;
+
+ /// Default number of octaves for the noise::module::Perlin noise module.
+ static final int DEFAULT_PERLIN_OCTAVE_COUNT = 6;
+
+ /// Default persistence value for the noise::module::Perlin noise module.
+ static final double DEFAULT_PERLIN_PERSISTENCE = 0.5;
+
+ /// Default noise quality for the noise::module::Perlin noise module.
+ static final NoiseQuality DEFAULT_PERLIN_QUALITY = NoiseQuality.QUALITY_STD;
+
+ /// Default noise seed for the noise::module::Perlin noise module.
+ static final int DEFAULT_PERLIN_SEED = 0;
+
+ /// Maximum number of octaves for the noise::module::Perlin noise module.
+ static final int PERLIN_MAX_OCTAVE = 30;
+
+
+ /// Frequency of the first octave.
+ double frequency;
+
+ /// Frequency multiplier between successive octaves.
+ double lacunarity;
+
+ /// Quality of the Perlin noise.
+ NoiseQuality noiseQuality;
+
+ /// Total number of octaves that generate the Perlin noise.
+ int octaveCount;
+
+ /// Persistence of the Perlin noise.
+ double persistence;
+
+ /// Seed value used by the Perlin-noise function.
+ int seed;
+
+
+ public Perlin ()
+ {
+ super(0);
+ frequency = DEFAULT_PERLIN_FREQUENCY;
+ lacunarity = DEFAULT_PERLIN_LACUNARITY;
+ noiseQuality = DEFAULT_PERLIN_QUALITY;
+ octaveCount = DEFAULT_PERLIN_OCTAVE_COUNT;
+ persistence = DEFAULT_PERLIN_PERSISTENCE;
+ seed = DEFAULT_PERLIN_SEED;
+ }
+
+ public double getValue (double x, double y, double z)
+ {
+ double value = 0.0;
+ double signal = 0.0;
+ double curPersistence = 1.0;
+ double nx, ny, nz;
+ int curSeed;
+
+ x *= frequency;
+ y *= frequency;
+ z *= frequency;
+
+ for (int curOctave = 0; curOctave < octaveCount; curOctave++)
+ {
+
+ // Make sure that these floating-point values have the same range as a 32-
+ // bit integer so that we can pass them to the coherent-noise functions.
+ nx = NoiseGen.MakeInt32Range (x);
+ ny = NoiseGen.MakeInt32Range (y);
+ nz = NoiseGen.MakeInt32Range (z);
+
+ // Get the coherent-noise value from the input value and add it to the
+ // final result.
+ curSeed = (seed + curOctave) & 0xffffffff;
+ signal = NoiseGen.GradientCoherentNoise3D (nx, ny, nz, curSeed, noiseQuality);
+ value += signal * curPersistence;
+
+ // Prepare the next octave.
+ x *= lacunarity;
+ y *= lacunarity;
+ z *= lacunarity;
+ curPersistence *= persistence;
+ }
+
+ return value;
+ }
+
+ /// Returns the frequency of the first octave.
+ ///
+ /// @returns The frequency of the first octave.
+ public double getFrequency ()
+ {
+ return frequency;
+ }
+
+ /// Returns the lacunarity of the Perlin noise.
+ ///
+ /// @returns The lacunarity of the Perlin noise.
+ ///
+ /// The lacunarity is the frequency multiplier between successive
+ /// octaves.
+ public double getLacunarity ()
+ {
+ return lacunarity;
+ }
+
+ /// Returns the quality of the Perlin noise.
+ ///
+ /// @returns The quality of the Perlin noise.
+ ///
+ /// See NoiseQuality for definitions of the various
+ /// coherent-noise qualities.
+ public NoiseQuality getNoiseQuality ()
+ {
+ return noiseQuality;
+ }
+
+ /// Returns the number of octaves that generate the Perlin noise.
+ ///
+ /// @returns The number of octaves that generate the Perlin noise.
+ ///
+ /// The number of octaves controls the amount of detail in the Perlin
+ /// noise.
+ public int getOctaveCount ()
+ {
+ return octaveCount;
+ }
+
+ /// Returns the persistence value of the Perlin noise.
+ ///
+ /// @returns The persistence value of the Perlin noise.
+ ///
+ /// The persistence value controls the roughness of the Perlin noise.
+ public double getPersistence ()
+ {
+ return persistence;
+ }
+
+ /// Returns the seed value used by the Perlin-noise function.
+ ///
+ /// @returns The seed value.
+ public int getSeed ()
+ {
+ return seed;
+ }
+
+ /// Sets the frequency of the first octave.
+ ///
+ /// @param frequency The frequency of the first octave.
+ public void setFrequency (double frequency)
+ {
+ this.frequency = frequency;
+ }
+
+ /// Sets the lacunarity of the Perlin noise.
+ ///
+ /// @param lacunarity The lacunarity of the Perlin noise.
+ ///
+ /// The lacunarity is the frequency multiplier between successive
+ /// octaves.
+ ///
+ /// For best results, set the lacunarity to a number between 1.5 and
+ /// 3.5.
+ public void setLacunarity (double lacunarity)
+ {
+ this.lacunarity = lacunarity;
+ }
+
+ /// Sets the quality of the Perlin noise.
+ ///
+ /// @param noiseQuality The quality of the Perlin noise.
+ ///
+ /// See NoiseQuality for definitions of the various
+ /// coherent-noise qualities.
+ public void setNoiseQuality (NoiseQuality noiseQuality)
+ {
+ this.noiseQuality = noiseQuality;
+ }
+
+ /// Sets the number of octaves that generate the Perlin noise.
+ ///
+ /// @param octaveCount The number of octaves that generate the Perlin
+ /// noise.
+ ///
+ /// @pre The number of octaves ranges from 1 to PERLIN_MAX_OCTAVE.
+ ///
+ /// @throw noise::ExceptionInvalidParam An invalid parameter was
+ /// specified; see the preconditions for more information.
+ ///
+ /// The number of octaves controls the amount of detail in the Perlin
+ /// noise.
+ ///
+ /// The larger the number of octaves, the more time required to
+ /// calculate the Perlin-noise value.
+ public void setOctaveCount (int octaveCount) throws ExceptionInvalidParam
+ {
+ if (octaveCount < 1 || octaveCount > PERLIN_MAX_OCTAVE)
+ {
+ throw new ExceptionInvalidParam ("Invalid parameter In Perlin Noise Module");
+ }
+
+ this.octaveCount = octaveCount;
+ }
+
+ /// Sets the persistence value of the Perlin noise.
+ ///
+ /// @param persistence The persistence value of the Perlin noise.
+ ///
+ /// The persistence value controls the roughness of the Perlin noise.
+ ///
+ /// For best results, set the persistence to a number between 0.0 and
+ /// 1.0.
+ public void setPersistence (double persistence)
+ {
+ this.persistence = persistence;
+ }
+
+ /// Sets the seed value used by the Perlin-noise function.
+ ///
+ /// @param seed The seed value.
+ public void setSeed (int seed)
+ {
+ this.seed = seed;
+ }
+
+}
diff --git a/src/libnoiseforjava/module/Power.java b/src/libnoiseforjava/module/Power.java new file mode 100644 index 0000000..53484a9 --- /dev/null +++ b/src/libnoiseforjava/module/Power.java @@ -0,0 +1,56 @@ +/*
+ * Copyright (C) 2003, 2004 Jason Bevins (original libnoise code)
+ * Copyright 2010 Thomas J. Hodge (java port of libnoise)
+ *
+ * This file is part of libnoiseforjava.
+ *
+ * libnoiseforjava is a Java port of the C++ library libnoise, which may be found at
+ * http://libnoise.sourceforge.net/. libnoise was developed by Jason Bevins, who may be
+ * contacted at [email protected] (for great email, take off every 'zig').
+ * Porting to Java was done by Thomas Hodge, who may be contacted at
+ * [email protected] (remove every 'zag').
+ *
+ * libnoiseforjava is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * libnoiseforjava is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * libnoiseforjava. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package libnoiseforjava.module;
+
+import libnoiseforjava.exception.ExceptionInvalidParam;
+
+public class Power extends ModuleBase
+{
+ /// Noise module that raises the output value from a first source module
+ /// to the power of the output value from a second source module.
+ ///
+ /// The first source module must have an index value of 0.
+ ///
+ /// The second source module must have an index value of 1.
+ ///
+ /// This noise module requires two source modules.
+
+ public Power (ModuleBase sourceModuleOne, ModuleBase sourceModuleTwo) throws ExceptionInvalidParam
+ {
+ super(2);
+ setSourceModule(0, sourceModuleOne);
+ setSourceModule(1, sourceModuleTwo);
+ }
+
+ public double getValue (double x, double y, double z)
+ {
+ assert (sourceModules[0] != null);
+ assert (sourceModules[1] != null);
+
+ return Math.pow (sourceModules[0].getValue (x, y, z),
+ sourceModules[1].getValue (x, y, z));
+ }
+}
diff --git a/src/libnoiseforjava/module/RidgedMulti.java b/src/libnoiseforjava/module/RidgedMulti.java new file mode 100644 index 0000000..c1a2d4c --- /dev/null +++ b/src/libnoiseforjava/module/RidgedMulti.java @@ -0,0 +1,357 @@ +/*
+ * Copyright (C) 2003, 2004 Jason Bevins (original libnoise code)
+ * Copyright 2010 Thomas J. Hodge (java port of libnoise)
+ *
+ * This file is part of libnoiseforjava.
+ *
+ * libnoiseforjava is a Java port of the C++ library libnoise, which may be found at
+ * http://libnoise.sourceforge.net/. libnoise was developed by Jason Bevins, who may be
+ * contacted at [email protected] (for great email, take off every 'zig').
+ * Porting to Java was done by Thomas Hodge, who may be contacted at
+ * [email protected] (remove every 'zag').
+ *
+ * libnoiseforjava is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * libnoiseforjava is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * libnoiseforjava. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package libnoiseforjava.module;
+
+import libnoiseforjava.NoiseGen;
+import libnoiseforjava.NoiseGen.NoiseQuality;
+import libnoiseforjava.exception.ExceptionInvalidParam;
+
+public class RidgedMulti extends ModuleBase
+{
+ /// Noise module that outputs 3-dimensional ridged-multifractal noise.
+ ///
+ /// This noise module, heavily based on the Perlin-noise module, generates
+ /// ridged-multifractal noise. Ridged-multifractal noise is generated in
+ /// much of the same way as Perlin noise, except the output of each octave
+ /// is modified by an absolute-value function. Modifying the octave
+ /// values in this way produces ridge-like formations.
+ ///
+ /// Ridged-multifractal noise does not use a persistence value. This is
+ /// because the persistence values of the octaves are based on the values
+ /// generated from from previous octaves, creating a feedback loop (or
+ /// that's what it looks like after reading the code.)
+ ///
+ /// This noise module outputs ridged-multifractal-noise values that
+ /// usually range from -1.0 to +1.0, but there are no guarantees that all
+ /// output values will exist within that range.
+ ///
+ /// @note For ridged-multifractal noise generated with only one octave,
+ /// the output value ranges from -1.0 to 0.0.
+ ///
+ /// Ridged-multifractal noise is often used to generate craggy mountainous
+ /// terrain or marble-like textures.
+ ///
+ /// This noise module does not require any source modules.
+ ///
+ /// <b>Octaves</b>
+ ///
+ /// The number of octaves control the <i>amount of detail</i> of the
+ /// ridged-multifractal noise. Adding more octaves increases the detail
+ /// of the ridged-multifractal noise, but with the drawback of increasing
+ /// the calculation time.
+ ///
+ /// An application may specify the number of octaves that generate
+ /// ridged-multifractal noise by calling the setOctaveCount() method.
+ ///
+ /// <b>Frequency</b>
+ ///
+ /// An application may specify the frequency of the first octave by
+ /// calling the setFrequency() method.
+ ///
+ /// <b>Lacunarity</b>
+ ///
+ /// The lacunarity specifies the frequency multipler between successive
+ /// octaves.
+ ///
+ /// The effect of modifying the lacunarity is subtle; you may need to play
+ /// with the lacunarity value to determine the effects. For best results,
+ /// set the lacunarity to a number between 1.5 and 3.5.
+ ///
+ /// <b>References & Acknowledgments</b>
+ ///
+ /// <a href=http://www.texturingandmodeling.com/Musgrave.html>F.
+ /// Kenton "Doc Mojo" Musgrave's texturing page</a> - This page contains
+ /// links to source code that generates ridged-multfractal noise, among
+ /// other types of noise. The source file <a
+ /// href=http://www.texturingandmodeling.com/CODE/MUSGRAVE/CLOUD/fractal.c>
+ /// fractal.c</a> contains the code I used in my ridged-multifractal class
+ /// (see the @a RidgedMultifractal() function.) This code was written by F.
+ /// Kenton Musgrave, the person who created
+ /// <a href=http://www.pandromeda.com/>MojoWorld</a>. He is also one of
+ /// the authors in <i>Texturing and Modeling: A Procedural Approach</i>
+ /// (Morgan Kaufmann, 2002. ISBN 1-55860-848-6.)
+
+ /// Default frequency for the noise::module::RidgedMulti noise module.
+ static final double DEFAULT_RIDGED_FREQUENCY = 1.0;
+
+ /// Default lacunarity for the noise::module::RidgedMulti noise module.
+ static final double DEFAULT_RIDGED_LACUNARITY = 2.0;
+
+ /// Default number of octaves for the noise::module::RidgedMulti noise
+ /// module.
+ static final int DEFAULT_RIDGED_OCTAVE_COUNT = 6;
+
+ /// Default noise quality for the noise::module::RidgedMulti noise
+ /// module.
+ static final NoiseQuality DEFAULT_RIDGED_QUALITY = NoiseQuality.QUALITY_STD;
+
+ /// Default noise seed for the noise::module::RidgedMulti noise module.
+ static final int DEFAULT_RIDGED_SEED = 0;
+
+ /// Maximum number of octaves for the noise::module::RidgedMulti noise
+ /// module.
+ static final int RIDGED_MAX_OCTAVE = 30;
+
+ /// Frequency of the first octave.
+ double frequency;
+
+ /// Frequency multiplier between successive octaves.
+ double lacunarity;
+
+ /// Quality of the ridged-multifractal noise.
+ NoiseQuality noiseQuality;
+
+ /// Total number of octaves that generate the ridged-multifractal
+ /// noise.
+ int octaveCount;
+
+ /// Contains the spectral weights for each octave.
+ double [] spectralWeights = new double[RIDGED_MAX_OCTAVE];
+
+ /// Seed value used by the ridged-multfractal-noise function.
+ int seed;
+
+
+ public RidgedMulti ()
+ {
+ super(0);
+ frequency = DEFAULT_RIDGED_FREQUENCY;
+ lacunarity = DEFAULT_RIDGED_LACUNARITY;
+ noiseQuality = DEFAULT_RIDGED_QUALITY;
+ octaveCount = DEFAULT_RIDGED_OCTAVE_COUNT;
+ seed = DEFAULT_RIDGED_SEED;
+
+ calcSpectralWeights();
+ }
+
+ // Calculates the spectral weights for each octave.
+ public void calcSpectralWeights ()
+ {
+ // This exponent parameter should be user-defined; it may be exposed in a
+ // future version of libnoise.
+ double h = 1.0;
+
+ double frequency = 1.0;
+ for (int i = 0; i < RIDGED_MAX_OCTAVE; i++) {
+ // Compute weight for each frequency.
+ this.spectralWeights[i] = Math.pow (frequency, -h);
+ frequency *= lacunarity;
+ }
+ }
+
+ // Multifractal code originally written by F. Kenton "Doc Mojo" Musgrave,
+ // 1998. Modified by jas for use with libnoise.
+ public double getValue (double x, double y, double z)
+ {
+ x *= frequency;
+ y *= frequency;
+ z *= frequency;
+
+ double signal = 0.0;
+ double value = 0.0;
+ double weight = 1.0;
+
+ // These parameters should be user-defined; they may be exposed in a
+ // future version of libnoiseforjava.
+ double offset = 1.0;
+ double gain = 2.0;
+
+ for (int curOctave = 0; curOctave < octaveCount; curOctave++)
+ {
+ // Make sure that these floating-point values have the same range as a 32-
+ // bit integer so that we can pass them to the coherent-noise functions.
+ double nx, ny, nz;
+ nx = NoiseGen.MakeInt32Range (x);
+ ny = NoiseGen.MakeInt32Range (y);
+ nz = NoiseGen.MakeInt32Range (z);
+
+ // Get the coherent-noise value.
+ int curSeed = (seed + curOctave) & 0x7fffffff;
+ signal = NoiseGen.GradientCoherentNoise3D (nx, ny, nz, curSeed, noiseQuality);
+
+ // Make the ridges.
+ signal = Math.abs (signal);
+ signal = offset - signal;
+
+ // Square the signal to increase the sharpness of the ridges.
+ signal *= signal;
+
+ // The weighting from the previous octave is applied to the signal.
+ // Larger values have higher weights, producing sharp points along the
+ // ridges.
+ signal *= weight;
+
+ // Weight successive contributions by the previous signal.
+ weight = signal * gain;
+ if (weight > 1.0)
+ weight = 1.0;
+ if (weight < 0.0)
+ weight = 0.0;
+
+
+ // Add the signal to the output value.
+ value += (signal * spectralWeights[curOctave]);
+
+ // Go to the next octave.
+ x *= lacunarity;
+ y *= lacunarity;
+ z *= lacunarity;
+ }
+
+ return (value * 1.25) - 1.0;
+ }
+
+ public double getFrequency ()
+ {
+ return frequency;
+ }
+
+ /// Returns the lacunarity of the ridged-multifractal noise.
+ ///
+ /// @returns The lacunarity of the ridged-multifractal noise.
+ ///
+ /// The lacunarity is the frequency multiplier between successive
+ /// octaves.
+ public double getLacunarity ()
+ {
+ return lacunarity;
+ }
+
+ /// Returns the quality of the ridged-multifractal noise.
+ ///
+ /// @returns The quality of the ridged-multifractal noise.
+ ///
+ /// See noise::NoiseQuality for definitions of the various
+ /// coherent-noise qualities.
+ public NoiseQuality getNoiseQuality ()
+ {
+ return noiseQuality;
+ }
+
+ /// Returns the number of octaves that generate the
+ /// ridged-multifractal noise.
+ ///
+ /// @returns The number of octaves that generate the
+ /// ridged-multifractal noise.
+ ///
+ /// The number of octaves controls the amount of detail in the
+ /// ridged-multifractal noise.
+ public int getOctaveCount ()
+ {
+ return octaveCount;
+ }
+
+ /// Returns the seed value used by the ridged-multifractal-noise
+ /// function.
+ ///
+ /// @returns The seed value.
+ public int getSeed ()
+ {
+ return seed;
+ }
+
+
+ /// Sets the frequency of the first octave.
+ ///
+ /// @param frequency The frequency of the first octave.
+ public void setFrequency (double frequency)
+ {
+ this.frequency = frequency;
+ }
+
+ /// Sets the lacunarity of the ridged-multifractal noise.
+ ///
+ /// @param lacunarity The lacunarity of the ridged-multifractal noise.
+ ///
+ /// The lacunarity is the frequency multiplier between successive
+ /// octaves.
+ ///
+ /// For best results, set the lacunarity to a number between 1.5 and
+ /// 3.5.
+ public void setLacunarity (double lacunarity)
+ {
+ this.lacunarity = lacunarity;
+ calcSpectralWeights ();
+ }
+
+ /// Sets the quality of the ridged-multifractal noise.
+ ///
+ /// @param noiseQuality The quality of the ridged-multifractal noise.
+ ///
+ /// See NoiseQuality for definitions of the various
+ /// coherent-noise qualities.
+ public void setNoiseQuality (NoiseQuality noiseQuality)
+ {
+ this.noiseQuality = noiseQuality;
+ }
+
+ /// Sets the number of octaves that generate the ridged-multifractal
+ /// noise.
+ ///
+ /// @param octaveCount The number of octaves that generate the
+ /// ridged-multifractal noise.
+ ///
+ /// @pre The number of octaves ranges from 1 to RIDGED_MAX_OCTAVE.
+ ///
+ /// @throw ExceptionInvalidParam An invalid parameter was
+ /// specified; see the preconditions for more information.
+ ///
+ /// The number of octaves controls the amount of detail in the
+ /// ridged-multifractal noise.
+ ///
+ /// The larger the number of octaves, the more time required to
+ /// calculate the ridged-multifractal-noise value.
+ public void setOctaveCount (int octaveCount) throws ExceptionInvalidParam
+ {
+ if (octaveCount > RIDGED_MAX_OCTAVE)
+ {
+ throw new ExceptionInvalidParam ("An invalid parameter was passed" +
+ " to a libnoise function or method.");
+ }
+
+ this.octaveCount = octaveCount;
+ }
+
+ /// Sets the seed value used by the ridged-multifractal-noise
+ /// function.
+ ///
+ /// @param seed The seed value.
+ public void setSeed (int seed)
+ {
+ this.seed = seed;
+ }
+
+ public double[] getSpectralWeights()
+ {
+ return spectralWeights;
+ }
+
+ public void setSpectralWeights(double[] spectralWeights)
+ {
+ this.spectralWeights = spectralWeights;
+ }
+
+}
diff --git a/src/libnoiseforjava/module/RotatePoint.java b/src/libnoiseforjava/module/RotatePoint.java new file mode 100644 index 0000000..a1a57b5 --- /dev/null +++ b/src/libnoiseforjava/module/RotatePoint.java @@ -0,0 +1,216 @@ +/*
+ * Copyright (C) 2003, 2004 Jason Bevins (original libnoise code)
+ * Copyright 2010 Thomas J. Hodge (java port of libnoise)
+ *
+ * This file is part of libnoiseforjava.
+ *
+ * libnoiseforjava is a Java port of the C++ library libnoise, which may be found at
+ * http://libnoise.sourceforge.net/. libnoise was developed by Jason Bevins, who may be
+ * contacted at [email protected] (for great email, take off every 'zig').
+ * Porting to Java was done by Thomas Hodge, who may be contacted at
+ * [email protected] (remove every 'zag').
+ *
+ * libnoiseforjava is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * libnoiseforjava is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * libnoiseforjava. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package libnoiseforjava.module;
+
+import libnoiseforjava.exception.ExceptionInvalidParam;
+
+public class RotatePoint extends ModuleBase
+{
+ /// Noise module that rotates the input value around the origin before
+ /// returning the output value from a source module.
+ ///
+ /// The getValue() method rotates the coordinates of the input value
+ /// around the origin before returning the output value from the source
+ /// module. To set the rotation angles, call the setAngles() method. To
+ /// set the rotation angle around the individual @a x, @a y, or @a z axes,
+ /// call the setXAngle(), setYAngle() or setZAngle() methods,
+ /// respectively.
+ ///
+ /// The coordinate system of the input value is assumed to be
+ /// "left-handed" (@a x increases to the right, @a y increases upward,
+ /// and @a z increases inward.)
+ ///
+ /// This noise module requires one source module.
+
+ /// Default @a x rotation angle for the RotatePoint noise
+ /// module.
+ static final double DEFAULT_ROTATE_X = 0.0;
+
+ /// Default @a y rotation angle for the RotatePoint noise
+ /// module.
+ static final double DEFAULT_ROTATE_Y = 0.0;
+
+ /// Default @a z rotation angle for the RotatePoint noise
+ /// module.
+ static final double DEFAULT_ROTATE_Z = 0.0;
+
+
+ /// An entry within the 3x3 rotation matrix used for rotating the
+ /// input value.
+ double x1Matrix;
+
+ /// An entry within the 3x3 rotation matrix used for rotating the
+ /// input value.
+ double x2Matrix;
+
+ /// An entry within the 3x3 rotation matrix used for rotating the
+ /// input value.
+ double x3Matrix;
+
+ /// @a x rotation angle applied to the input value, in degrees.
+ double xAngle;
+
+ /// An entry within the 3x3 rotation matrix used for rotating the
+ /// input value.
+ double y1Matrix;
+
+ /// An entry within the 3x3 rotation matrix used for rotating the
+ /// input value.
+ double y2Matrix;
+
+ /// An entry within the 3x3 rotation matrix used for rotating the
+ /// input value.
+ double y3Matrix;
+
+ /// @a y rotation angle applied to the input value, in degrees.
+ double yAngle;
+
+ /// An entry within the 3x3 rotation matrix used for rotating the
+ /// input value.
+ double z1Matrix;
+
+ /// An entry within the 3x3 rotation matrix used for rotating the
+ /// input value.
+ double z2Matrix;
+
+ /// An entry within the 3x3 rotation matrix used for rotating the
+ /// input value.
+ double z3Matrix;
+
+ /// @a z rotation angle applied to the input value, in degrees.
+ double zAngle;
+
+
+ public RotatePoint (ModuleBase sourceModule) throws ExceptionInvalidParam
+ {
+ super(1);
+ setSourceModule(0, sourceModule);
+ setAngles (DEFAULT_ROTATE_X, DEFAULT_ROTATE_Y, DEFAULT_ROTATE_Z);
+ }
+
+ public double getValue (double x, double y, double z)
+ {
+ assert (sourceModules[0] != null);
+
+ double nx = (x1Matrix * x) + (y1Matrix * y) + (z1Matrix * z);
+ double ny = (x2Matrix * x) + (y2Matrix * y) + (z2Matrix * z);
+ double nz = (x3Matrix * x) + (y3Matrix * y) + (z3Matrix * z);
+ return sourceModules[0].getValue (nx, ny, nz);
+ }
+
+ public void setAngles (double xAngle, double yAngle,
+ double zAngle)
+ {
+ double xCos, yCos, zCos, xSin, ySin, zSin;
+ xCos = Math.cos (Math.toRadians(xAngle));
+ yCos = Math.cos (Math.toRadians(yAngle));
+ zCos = Math.cos (Math.toRadians(zAngle));
+ xSin = Math.sin (Math.toRadians(xAngle));
+ ySin = Math.sin (Math.toRadians(yAngle));
+ zSin = Math.sin (Math.toRadians(zAngle));
+
+ x1Matrix = ySin * xSin * zSin + yCos * zCos;
+ y1Matrix = xCos * zSin;
+ z1Matrix = ySin * zCos - yCos * xSin * zSin;
+ x2Matrix = ySin * xSin * zCos - yCos * zSin;
+ y2Matrix = xCos * zCos;
+ z2Matrix = -yCos * xSin * zCos - ySin * zSin;
+ x3Matrix = -ySin * xCos;
+ y3Matrix = xSin;
+ z3Matrix = yCos * xCos;
+
+ this.xAngle = xAngle;
+ this.yAngle = yAngle;
+ this.zAngle = zAngle;
+ }
+
+ /// Returns the rotation angle around the @a x axis to apply to the
+ /// input value.
+ ///
+ /// @returns The rotation angle around the @a x axis, in degrees.
+ public double getXAngle ()
+ {
+ return xAngle;
+ }
+
+ /// Returns the rotation angle around the @a y axis to apply to the
+ /// input value.
+ ///
+ /// @returns The rotation angle around the @a y axis, in degrees.
+ public double getYAngle ()
+ {
+ return yAngle;
+ }
+
+ /// Returns the rotation angle around the @a z axis to apply to the
+ /// input value.
+ ///
+ /// @returns The rotation angle around the @a z axis, in degrees.
+ public double getZAngle ()
+ {
+ return zAngle;
+ }
+
+ /// Sets the rotation angle around the @a x axis to apply to the input
+ /// value.
+ ///
+ /// @param xAngle The rotation angle around the @a x axis, in degrees.
+ ///
+ /// The getValue() method rotates the coordinates of the input value
+ /// around the origin before returning the output value from the
+ /// source module.
+ public void setXAngle (double xAngle)
+ {
+ setAngles (xAngle, this.yAngle, this.zAngle);
+ }
+
+ /// Sets the rotation angle around the @a y axis to apply to the input
+ /// value.
+ ///
+ /// @param yAngle The rotation angle around the @a y axis, in degrees.
+ ///
+ /// The getValue() method rotates the coordinates of the input value
+ /// around the origin before returning the output value from the
+ /// source module.
+ public void SetYAngle (double yAngle)
+ {
+ setAngles (this.xAngle, yAngle, this.zAngle);
+ }
+
+ /// Sets the rotation angle around the @a z axis to apply to the input
+ /// value.
+ ///
+ /// @param zAngle The rotation angle around the @a z axis, in degrees.
+ ///
+ /// The getValue() method rotates the coordinates of the input value
+ /// around the origin before returning the output value from the
+ /// source module.
+ public void SetZAngle (double zAngle)
+ {
+ setAngles (this.xAngle, this.yAngle, zAngle);
+ }
+
+}
diff --git a/src/libnoiseforjava/module/ScaleBias.java b/src/libnoiseforjava/module/ScaleBias.java new file mode 100644 index 0000000..66daea4 --- /dev/null +++ b/src/libnoiseforjava/module/ScaleBias.java @@ -0,0 +1,124 @@ +/*
+ * Copyright (C) 2003, 2004 Jason Bevins (original libnoise code)
+ * Copyright 2010 Thomas J. Hodge (java port of libnoise)
+ *
+ * This file is part of libnoiseforjava.
+ *
+ * libnoiseforjava is a Java port of the C++ library libnoise, which may be found at
+ * http://libnoise.sourceforge.net/. libnoise was developed by Jason Bevins, who may be
+ * contacted at [email protected] (for great email, take off every 'zig').
+ * Porting to Java was done by Thomas Hodge, who may be contacted at
+ * [email protected] (remove every 'zag').
+ *
+ * libnoiseforjava is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * libnoiseforjava is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * libnoiseforjava. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package libnoiseforjava.module;
+
+import libnoiseforjava.exception.ExceptionInvalidParam;
+
+public class ScaleBias extends ModuleBase
+{
+
+ /// Noise module that applies a scaling factor and a bias to the output
+ /// value from a source module.
+ ///
+ /// The getValue() method retrieves the output value from the source
+ /// module, multiplies it with a scaling factor, adds a bias to it, then
+ /// outputs the value.
+ ///
+ /// This noise module requires one source module.
+
+ /// Default bias for the ScaleBias noise module.
+ static final double DEFAULT_BIAS = 0.0;
+
+ /// Default scale for the ScaleBias noise module.
+ static final double DEFAULT_SCALE = 1.0;
+
+ /// Bias to apply to the scaled output value from the source module.
+ double bias;
+
+ /// Scaling factor to apply to the output value from the source
+ /// module.
+ double scale;
+
+
+ public ScaleBias (ModuleBase sourceModule) throws ExceptionInvalidParam
+ {
+ super(1);
+ setSourceModule(0, sourceModule);
+ bias = DEFAULT_BIAS;
+ scale = DEFAULT_SCALE;
+ }
+
+ public double getValue (double x, double y, double z)
+ {
+ assert (sourceModules[0] != null);
+
+ return sourceModules[0].getValue (x, y, z) * scale + bias;
+ }
+
+ /// Returns the bias to apply to the scaled output value from the
+ /// source module.
+ ///
+ /// @returns The bias to apply.
+ ///
+ /// The getValue() method retrieves the output value from the source
+ /// module, multiplies it with the scaling factor, adds the bias to
+ /// it, then outputs the value.
+ public double getBias ()
+ {
+ return bias;
+ }
+
+ /// Returns the scaling factor to apply to the output value from the
+ /// source module.
+ ///
+ /// @returns The scaling factor to apply.
+ ///
+ /// The getValue() method retrieves the output value from the source
+ /// module, multiplies it with the scaling factor, adds the bias to
+ /// it, then outputs the value.
+ public double getScale ()
+ {
+ return scale;
+ }
+
+
+ /// Sets the bias to apply to the scaled output value from the source
+ /// module.
+ ///
+ /// @param bias The bias to apply.
+ ///
+ /// The getValue() method retrieves the output value from the source
+ /// module, multiplies it with the scaling factor, adds the bias to
+ /// it, then outputs the value.
+ public void setBias (double bias)
+ {
+ this.bias = bias;
+ }
+
+ /// Sets the scaling factor to apply to the output value from the
+ /// source module.
+ ///
+ /// @param scale The scaling factor to apply.
+ ///
+ /// The getValue() method retrieves the output value from the source
+ /// module, multiplies it with the scaling factor, adds the bias to
+ /// it, then outputs the value.
+ public void setScale (double scale)
+ {
+ this.scale = scale;
+ }
+
+}
diff --git a/src/libnoiseforjava/module/ScalePoint.java b/src/libnoiseforjava/module/ScalePoint.java new file mode 100644 index 0000000..f0c10ce --- /dev/null +++ b/src/libnoiseforjava/module/ScalePoint.java @@ -0,0 +1,182 @@ +/*
+ * Copyright (C) 2003, 2004 Jason Bevins (original libnoise code)
+ * Copyright 2010 Thomas J. Hodge (java port of libnoise)
+ *
+ * This file is part of libnoiseforjava.
+ *
+ * libnoiseforjava is a Java port of the C++ library libnoise, which may be found at
+ * http://libnoise.sourceforge.net/. libnoise was developed by Jason Bevins, who may be
+ * contacted at [email protected] (for great email, take off every 'zig').
+ * Porting to Java was done by Thomas Hodge, who may be contacted at
+ * [email protected] (remove every 'zag').
+ *
+ * libnoiseforjava is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * libnoiseforjava is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * libnoiseforjava. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package libnoiseforjava.module;
+
+import libnoiseforjava.exception.ExceptionInvalidParam;
+
+public class ScalePoint extends ModuleBase
+{
+
+ /// Noise module that scales the coordinates of the input value before
+ /// returning the output value from a source module.
+ ///
+ /// The getValue() method multiplies the ( @a x, @a y, @a z ) coordinates
+ /// of the input value with a scaling factor before returning the output
+ /// value from the source module. To set the scaling factor, call the
+ /// setScale() method. To set the scaling factor to apply to the
+ /// individual @a x, @a y, or @a z coordinates, call the setXScale(),
+ /// setYScale() or setZScale() methods, respectively.
+ ///
+ /// This noise module requires one source module.
+
+ // Default scaling factor applied to the @a x coordinate for the
+ /// ScalePoint noise module.
+ static final double DEFAULT_SCALE_POINT_X = 1.0;
+
+ /// Default scaling factor applied to the @a y coordinate for the
+ /// ScalePoint noise module.
+ static final double DEFAULT_SCALE_POINT_Y = 1.0;
+
+ /// Default scaling factor applied to the @a z coordinate for the
+ /// ScalePoint noise module.
+ static final double DEFAULT_SCALE_POINT_Z = 1.0;
+
+ /// Scaling factor applied to the @a x coordinate of the input value.
+ double xScale;
+
+ /// Scaling factor applied to the @a y coordinate of the input value.
+ double yScale;
+
+ /// Scaling factor applied to the @a z coordinate of the input value.
+ double zScale;
+
+
+ public ScalePoint (ModuleBase sourceModule) throws ExceptionInvalidParam
+ {
+ super(1);
+ setSourceModule(0, sourceModule);
+
+ xScale = DEFAULT_SCALE_POINT_X;
+ yScale = DEFAULT_SCALE_POINT_Y;
+ zScale = DEFAULT_SCALE_POINT_Z;
+ }
+
+ public double getValue (double x, double y, double z)
+ {
+ assert (sourceModules[0] != null);
+
+ return sourceModules[0].getValue (x * xScale, y * yScale,
+ z * zScale);
+ }
+
+ /// Returns the scaling factor applied to the @a x coordinate of the
+ /// input value.
+ ///
+ /// @returns The scaling factor applied to the @a x coordinate.
+ public double getXScale ()
+ {
+ return xScale;
+ }
+
+ /// Returns the scaling factor applied to the @a y coordinate of the
+ /// input value.
+ ///
+ /// @returns The scaling factor applied to the @a y coordinate.
+ public double getYScale ()
+ {
+ return yScale;
+ }
+
+ /// Returns the scaling factor applied to the @a z coordinate of the
+ /// input value.
+ ///
+ /// @returns The scaling factor applied to the @a z coordinate.
+ public double getZScale ()
+ {
+ return zScale;
+ }
+
+ /// Sets the scaling factor to apply to the input value.
+ ///
+ /// @param scale The scaling factor to apply.
+ ///
+ /// The getValue() method multiplies the ( @a x, @a y, @a z )
+ /// coordinates of the input value with a scaling factor before
+ /// returning the output value from the source module.
+ public void setScale (double scale)
+ {
+ this.xScale = scale;
+ this.yScale = scale;
+ this.zScale = scale;
+ }
+
+ /// Sets the scaling factor to apply to the ( @a x, @a y, @a z )
+ /// coordinates of the input value.
+ ///
+ /// @param xScale The scaling factor to apply to the @a x coordinate.
+ /// @param yScale The scaling factor to apply to the @a y coordinate.
+ /// @param zScale The scaling factor to apply to the @a z coordinate.
+ ///
+ /// The getValue() method multiplies the ( @a x, @a y, @a z )
+ /// coordinates of the input value with a scaling factor before
+ /// returning the output value from the source module.
+ public void setScale (double xScale, double yScale, double zScale)
+ {
+ this.xScale = xScale;
+ this.yScale = yScale;
+ this.zScale = zScale;
+ }
+
+ /// Sets the scaling factor to apply to the @a x coordinate of the
+ /// input value.
+ ///
+ /// @param xScale The scaling factor to apply to the @a x coordinate.
+ ///
+ /// The getValue() method multiplies the ( @a x, @a y, @a z )
+ /// coordinates of the input value with a scaling factor before
+ /// returning the output value from the source module.
+ public void setXScale (double xScale)
+ {
+ this.xScale = xScale;
+ }
+
+ /// Sets the scaling factor to apply to the @a y coordinate of the
+ /// input value.
+ ///
+ /// @param yScale The scaling factor to apply to the @a y coordinate.
+ ///
+ /// The getValue() method multiplies the ( @a x, @a y, @a z )
+ /// coordinates of the input value with a scaling factor before
+ /// returning the output value from the source module.
+ public void setYScale (double yScale)
+ {
+ this.yScale = yScale;
+ }
+
+ /// Sets the scaling factor to apply to the @a z coordinate of the
+ /// input value.
+ ///
+ /// @param zScale The scaling factor to apply to the @a z coordinate.
+ ///
+ /// The getValue() method multiplies the ( @a x, @a y, @a z )
+ /// coordinates of the input value with a scaling factor before
+ /// returning the output value from the source module.
+ public void setZScale (double zScale)
+ {
+ this.zScale = zScale;
+ }
+
+}
diff --git a/src/libnoiseforjava/module/Select.java b/src/libnoiseforjava/module/Select.java new file mode 100644 index 0000000..d394aa3 --- /dev/null +++ b/src/libnoiseforjava/module/Select.java @@ -0,0 +1,300 @@ +/*
+ * Copyright (C) 2003, 2004 Jason Bevins (original libnoise code)
+ * Copyright 2010 Thomas J. Hodge (java port of libnoise)
+ *
+ * This file is part of libnoiseforjava.
+ *
+ * libnoiseforjava is a Java port of the C++ library libnoise, which may be found at
+ * http://libnoise.sourceforge.net/. libnoise was developed by Jason Bevins, who may be
+ * contacted at [email protected] (for great email, take off every 'zig').
+ * Porting to Java was done by Thomas Hodge, who may be contacted at
+ * [email protected] (remove every 'zag').
+ *
+ * libnoiseforjava is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * libnoiseforjava is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * libnoiseforjava. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package libnoiseforjava.module;
+
+import libnoiseforjava.Interp;
+import libnoiseforjava.exception.ExceptionInvalidParam;
+import libnoiseforjava.exception.ExceptionNoModule;
+
+public class Select extends ModuleBase
+{
+ /// Noise module that outputs the value selected from one of two source
+ /// modules chosen by the output value from a control module.
+ ///
+ /// Unlike most other noise modules, the index value assigned to a source
+ /// module determines its role in the selection operation:
+ /// - Source module 0 (upper left in the diagram) outputs a value.
+ /// - Source module 1 (lower left in the diagram) outputs a value.
+ /// - Source module 2 (bottom of the diagram) is known as the <i>control
+ /// module</i>. The control module determines the value to select. If
+ /// the output value from the control module is within a range of values
+ /// known as the <i>selection range</i>, this noise module outputs the
+ /// value from the source module with an index value of 1. Otherwise,
+ /// this noise module outputs the value from the source module with an
+ /// index value of 0.
+ ///
+ /// To specify the bounds of the selection range, call the setBounds()
+ /// method.
+ ///
+ /// An application can pass the control module to the setControlModule()
+ /// method instead of the setSourceModule() method. This may make the
+ /// application code easier to read.
+ ///
+ /// By default, there is an abrupt transition between the output values
+ /// from the two source modules at the selection-range boundary. To
+ /// smooth the transition, pass a non-zero value to the setEdgeFalloff()
+ /// method. Higher values result in a smoother transition.
+ ///
+ /// This noise module requires three source modules.
+
+ /// Default edge-falloff value for the Select noise module.
+ static final double DEFAULT_SELECT_EDGE_FALLOFF = 0.0;
+
+ /// Default lower bound of the selection range for the
+ /// Select noise module.
+ static final double DEFAULT_SELECT_LOWER_BOUND = -1.0;
+
+ /// Default upper bound of the selection range for the
+ /// Select noise module.
+ static final double DEFAULT_SELECT_UPPER_BOUND = 1.0;
+
+ /// Edge-falloff value.
+ double edgeFalloff;
+
+ /// Lower bound of the selection range.
+ double lowerBound;
+
+ /// Upper bound of the selection range.
+ double upperBound;
+
+
+ public Select (ModuleBase sourceModuleOne, ModuleBase sourceModuleTwo,
+ ModuleBase sourceModuleThree) throws ExceptionInvalidParam
+ {
+ super(3);
+ setSourceModule(0, sourceModuleOne);
+ setSourceModule(1, sourceModuleTwo);
+ setSourceModule(2, sourceModuleThree);
+
+ edgeFalloff = DEFAULT_SELECT_EDGE_FALLOFF;
+ lowerBound = DEFAULT_SELECT_LOWER_BOUND;
+ upperBound = DEFAULT_SELECT_UPPER_BOUND;
+ }
+
+ public double getValue (double x, double y, double z)
+ {
+ assert (sourceModules[0] != null);
+ assert (sourceModules[1] != null);
+ assert (sourceModules[2] != null);
+
+ double controlValue = sourceModules[2].getValue (x, y, z);
+ double alpha;
+
+ if (edgeFalloff > 0.0)
+ {
+ if (controlValue < (lowerBound - edgeFalloff))
+ // The output value from the control module is below the selector
+ // threshold; return the output value from the first source module.
+ return sourceModules[0].getValue (x, y, z);
+ else if (controlValue < (lowerBound + edgeFalloff))
+ {
+ // The output value from the control module is near the lower end of the
+ // selector threshold and within the smooth curve. Interpolate between
+ // the output values from the first and second source modules.
+ double lowerCurve = (lowerBound - edgeFalloff);
+ double upperCurve = (lowerBound + edgeFalloff);
+ alpha = Interp.SCurve3 (
+ (controlValue - lowerCurve) / (upperCurve - lowerCurve));
+ return Interp.linearInterp (sourceModules[0].getValue (x, y, z),
+ sourceModules[2].getValue (x, y, z),
+ alpha);
+ }
+ else if (controlValue < (upperBound - edgeFalloff))
+ // The output value from the control module is within the selector
+ // threshold; return the output value from the second source module.
+ return sourceModules[1].getValue (x, y, z);
+ else if (controlValue < (upperBound + edgeFalloff))
+ {
+ // The output value from the control module is near the upper end of the
+ // selector threshold and within the smooth curve. Interpolate between
+ // the output values from the first and second source modules.
+ double lowerCurve = (upperBound - edgeFalloff);
+ double upperCurve = (upperBound + edgeFalloff);
+ alpha = Interp.SCurve3 (
+ (controlValue - lowerCurve) / (upperCurve - lowerCurve));
+ return Interp.linearInterp (sourceModules[1].getValue (x, y, z),
+ sourceModules[0].getValue (x, y, z),
+ alpha);
+ }
+ else
+ // Output value from the control module is above the selector threshold;
+ // return the output value from the first source module.
+ return sourceModules[0].getValue (x, y, z);
+ }
+ else
+ {
+ if (controlValue < lowerBound || controlValue > upperBound)
+ return sourceModules[0].getValue (x, y, z);
+ else
+ return sourceModules[1].getValue (x, y, z);
+ }
+ }
+
+ /// Sets the lower and upper bounds of the selection range.
+ ///
+ /// @param lowerBound The lower bound.
+ /// @param upperBound The upper bound.
+ ///
+ /// @pre The lower bound must be less than or equal to the upper
+ /// bound.
+ public void setBounds (double lowerBound, double upperBound)
+ {
+ assert (lowerBound < upperBound);
+
+ this.lowerBound = lowerBound;
+ this.upperBound = upperBound;
+
+ // Make sure that the edge falloff curves do not overlap.
+ setEdgeFalloff (edgeFalloff);
+ }
+
+ /// Sets the falloff value at the edge transition.
+ ///
+ /// @param edgeFalloff The falloff value at the edge transition.
+ ///
+ /// The falloff value is the width of the edge transition at either
+ /// edge of the selection range.
+ ///
+ /// By default, there is an abrupt transition between the values from
+ /// the two source modules at the boundaries of the selection range.
+ ///
+ /// For example, if the selection range is 0.5 to 0.8, and the edge
+ /// falloff value is 0.1, then the getValue() method outputs:
+ /// - the output value from the source module with an index value of 0
+ /// if the output value from the control module is less than 0.4
+ /// ( = 0.5 - 0.1).
+ /// - a linear blend between the two output values from the two source
+ /// modules if the output value from the control module is between
+ /// 0.4 ( = 0.5 - 0.1) and 0.6 ( = 0.5 + 0.1).
+ /// - the output value from the source module with an index value of 1
+ /// if the output value from the control module is between 0.6
+ /// ( = 0.5 + 0.1) and 0.7 ( = 0.8 - 0.1).
+ /// - a linear blend between the output values from the two source
+ /// modules if the output value from the control module is between
+ /// 0.7 ( = 0.8 - 0.1 ) and 0.9 ( = 0.8 + 0.1).
+ /// - the output value from the source module with an index value of 0
+ /// if the output value from the control module is greater than 0.9
+ /// ( = 0.8 + 0.1).
+ public void setEdgeFalloff (double edgeFalloff)
+ {
+ // Make sure that the edge falloff curves do not overlap.
+ double boundSize = upperBound - lowerBound;
+ edgeFalloff = (edgeFalloff > boundSize / 2)? boundSize / 2: edgeFalloff;
+ }
+
+ /// Returns the control module.
+ ///
+ /// @returns A reference to the control module.
+ ///
+ /// @pre A control module has been added to this noise module via a
+ /// call to setSourceModule() or setControlModule().
+ ///
+ /// @throw ExceptionNoModule See the preconditions for more
+ /// information.
+ ///
+ /// The control module determines the output value to select. If the
+ /// output value from the control module is within a range of values
+ /// known as the <i>selection range</i>, the getValue() method outputs
+ /// the value from the source module with an index value of 1.
+ /// Otherwise, this method outputs the value from the source module
+ /// with an index value of 0.
+
+ // not sure this does what it says it does. Recheck original source
+ public ModuleBase getControlModule () throws ExceptionNoModule
+ {
+ if (sourceModules == null || sourceModules[2] == null) {
+ throw new ExceptionNoModule ("Could not retrieve a source module from a noise module.");
+ }
+ return (sourceModules[2]);
+ }
+
+ /// Returns the falloff value at the edge transition.
+ ///
+ /// @returns The falloff value at the edge transition.
+ ///
+ /// The falloff value is the width of the edge transition at either
+ /// edge of the selection range.
+ ///
+ /// By default, there is an abrupt transition between the output
+ /// values from the two source modules at the selection-range
+ /// boundary.
+ public double getEdgeFalloff ()
+ {
+ return edgeFalloff;
+ }
+
+ /// Returns the lower bound of the selection range.
+ ///
+ /// @returns The lower bound of the selection range.
+ ///
+ /// If the output value from the control module is within the
+ /// selection range, the getValue() method outputs the value from the
+ /// source module with an index value of 1. Otherwise, this method
+ /// outputs the value from the source module with an index value of 0.
+ public double getLowerBound ()
+ {
+ return lowerBound;
+ }
+
+ /// Returns the upper bound of the selection range.
+ ///
+ /// @returns The upper bound of the selection range.
+ ///
+ /// If the output value from the control module is within the
+ /// selection range, the getValue() method outputs the value from the
+ /// source module with an index value of 1. Otherwise, this method
+ /// outputs the value from the source module with an index value of 0.
+ public double getUpperBound ()
+ {
+ return upperBound;
+ }
+
+ /// Sets the control module.
+ ///
+ /// @param controlModule The control module.
+ ///
+ /// The control module determines the output value to select. If the
+ /// output value from the control module is within a range of values
+ /// known as the <i>selection range</i>, the getValue() method outputs
+ /// the value from the source module with an index value of 1.
+ /// Otherwise, this method outputs the value from the source module
+ /// with an index value of 0.
+ ///
+ /// This method assigns the control module an index value of 2.
+ /// Passing the control module to this method produces the same
+ /// results as passing the control module to the setSourceModule()
+ /// method while assigning that noise module an index value of 2.
+ ///
+ /// This control module must exist throughout the lifetime of this
+ /// noise module unless another control module replaces that control
+ /// module.
+ public void setControlModule (ModuleBase controlModule)
+ {
+ assert (sourceModules != null);
+ sourceModules[2] = controlModule;
+ }
+
+}
diff --git a/src/libnoiseforjava/module/Simplex.java b/src/libnoiseforjava/module/Simplex.java new file mode 100644 index 0000000..82d58c6 --- /dev/null +++ b/src/libnoiseforjava/module/Simplex.java @@ -0,0 +1,395 @@ +package libnoiseforjava.module;
+
+/**
+ * Michael Nugent
+ * Date: 3/9/12
+ * Time: 6:12 PM
+ * URL: https://github.com/michaelnugent/libnoiseforjava
+ * Package: libnoiseforjava.module
+ */
+
+
+/*
+* A speed-improved simplex noise algorithm for 2D, 3D and 4D in Java.
+*
+* Based on example code by Stefan Gustavson ([email protected]).
+* Optimisations by Peter Eastman ([email protected]).
+* Better rank ordering method by Stefan Gustavson in 2012.
+*
+* This could be speeded up even further, but it's useful as it is.
+*
+* Version 2012-03-09
+*
+* This code was placed in the public domain by its original author,
+* Stefan Gustavson. You may use it as you see fit, but
+* attribution is appreciated.
+*
+* Modified by Michael Nugent ([email protected]) for the
+* libnoise framework 20120309
+* All libnoise expects 3d, but I've left the 2d and 4d functions in for
+* reference.
+*
+*/
+
+public class Simplex extends ModuleBase { // Simplex noise in 2D, 3D and 4D
+ private static Grad grad3[] = {new Grad(1,1,0),new Grad(-1,1,0),new Grad(1,-1,0),new Grad(-1,-1,0),
+ new Grad(1,0,1),new Grad(-1,0,1),new Grad(1,0,-1),new Grad(-1,0,-1),
+ new Grad(0,1,1),new Grad(0,-1,1),new Grad(0,1,-1),new Grad(0,-1,-1)};
+
+ private static Grad grad4[]= {new Grad(0,1,1,1),new Grad(0,1,1,-1),new Grad(0,1,-1,1),new Grad(0,1,-1,-1),
+ new Grad(0,-1,1,1),new Grad(0,-1,1,-1),new Grad(0,-1,-1,1),new Grad(0,-1,-1,-1),
+ new Grad(1,0,1,1),new Grad(1,0,1,-1),new Grad(1,0,-1,1),new Grad(1,0,-1,-1),
+ new Grad(-1,0,1,1),new Grad(-1,0,1,-1),new Grad(-1,0,-1,1),new Grad(-1,0,-1,-1),
+ new Grad(1,1,0,1),new Grad(1,1,0,-1),new Grad(1,-1,0,1),new Grad(1,-1,0,-1),
+ new Grad(-1,1,0,1),new Grad(-1,1,0,-1),new Grad(-1,-1,0,1),new Grad(-1,-1,0,-1),
+ new Grad(1,1,1,0),new Grad(1,1,-1,0),new Grad(1,-1,1,0),new Grad(1,-1,-1,0),
+ new Grad(-1,1,1,0),new Grad(-1,1,-1,0),new Grad(-1,-1,1,0),new Grad(-1,-1,-1,0)};
+
+ private static short p[] = {151,160,137,91,90,15,
+ 131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142,8,99,37,240,21,10,23,
+ 190, 6,148,247,120,234,75,0,26,197,62,94,252,219,203,117,35,11,32,57,177,33,
+ 88,237,149,56,87,174,20,125,136,171,168, 68,175,74,165,71,134,139,48,27,166,
+ 77,146,158,231,83,111,229,122,60,211,133,230,220,105,92,41,55,46,245,40,244,
+ 102,143,54, 65,25,63,161, 1,216,80,73,209,76,132,187,208, 89,18,169,200,196,
+ 135,130,116,188,159,86,164,100,109,198,173,186, 3,64,52,217,226,250,124,123,
+ 5,202,38,147,118,126,255,82,85,212,207,206,59,227,47,16,58,17,182,189,28,42,
+ 223,183,170,213,119,248,152, 2,44,154,163, 70,221,153,101,155,167, 43,172,9,
+ 129,22,39,253, 19,98,108,110,79,113,224,232,178,185, 112,104,218,246,97,228,
+ 251,34,242,193,238,210,144,12,191,179,162,241, 81,51,145,235,249,14,239,107,
+ 49,192,214, 31,181,199,106,157,184, 84,204,176,115,121,50,45,127, 4,150,254,
+ 138,236,205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180};
+ // To remove the need for index wrapping, double the permutation table length
+ private short perm[] = new short[512];
+ private short permMod12[] = new short[512];
+
+ private double seed = 0;
+
+ public Simplex() {
+ super(0);
+ for(int i=0; i<512; i++) {
+ perm[i]=p[i & 255];
+ permMod12[i] = (short)(perm[i] % 12);
+ }
+ }
+
+ public double getSeed() {
+ return seed;
+ }
+
+ public void setSeed(double seed) {
+ this.seed = seed;
+ }
+
+ public void setSeed(int seed) {
+ this.seed = (double)seed;
+ }
+
+ // Skewing and unskewing factors for 2, 3, and 4 dimensions
+ private static final double F2 = 0.5*(Math.sqrt(3.0)-1.0);
+ private static final double G2 = (3.0-Math.sqrt(3.0))/6.0;
+ private static final double F3 = 1.0/3.0;
+ private static final double G3 = 1.0/6.0;
+ private static final double F4 = (Math.sqrt(5.0)-1.0)/4.0;
+ private static final double G4 = (5.0-Math.sqrt(5.0))/20.0;
+
+ // This method is a *lot* faster than using (int)Math.floor(x)
+ private static int fastfloor(double x) {
+ int xi = (int)x;
+ return x<xi ? xi-1 : xi;
+ }
+
+ private static double dot(Grad g, double x, double y) {
+ return g.x*x + g.y*y;
+ }
+
+ private static double dot(Grad g, double x, double y, double z) {
+ return g.x*x + g.y*y + g.z*z;
+ }
+
+ private static double dot(Grad g, double x, double y, double z, double w) {
+ return g.x*x + g.y*y + g.z*z + g.w*w;
+ }
+
+
+ // 2D simplex noise
+ public double getValue2d(double xin, double yin) {
+ double n0, n1, n2; // Noise contributions from the three corners
+ // Skew the input space to determine which simplex cell we're in
+ double s = (xin+yin)*F2; // Hairy factor for 2D
+ int i = fastfloor(xin+s);
+ int j = fastfloor(yin+s);
+ double t = (i+j)*G2;
+ double X0 = i-t; // Unskew the cell origin back to (x,y) space
+ double Y0 = j-t;
+ double x0 = xin-X0; // The x,y distances from the cell origin
+ double y0 = yin-Y0;
+ // For the 2D case, the simplex shape is an equilateral triangle.
+ // Determine which simplex we are in.
+ int i1, j1; // Offsets for second (middle) corner of simplex in (i,j) coords
+ if(x0>y0) {i1=1; j1=0;} // lower triangle, XY order: (0,0)->(1,0)->(1,1)
+ else {i1=0; j1=1;} // upper triangle, YX order: (0,0)->(0,1)->(1,1)
+ // A step of (1,0) in (i,j) means a step of (1-c,-c) in (x,y), and
+ // a step of (0,1) in (i,j) means a step of (-c,1-c) in (x,y), where
+ // c = (3-sqrt(3))/6
+ double x1 = x0 - i1 + G2; // Offsets for middle corner in (x,y) unskewed coords
+ double y1 = y0 - j1 + G2;
+ double x2 = x0 - 1.0 + 2.0 * G2; // Offsets for last corner in (x,y) unskewed coords
+ double y2 = y0 - 1.0 + 2.0 * G2;
+ // Work out the hashed gradient indices of the three simplex corners
+ int ii = i & 255;
+ int jj = j & 255;
+
+ int gi0 = permMod12[ii+perm[jj]];
+ int gi1 = permMod12[ii+i1+perm[jj+j1]];
+ int gi2 = permMod12[ii+1+perm[jj+1]];
+ // Calculate the contribution from the three corners
+ double t0 = 0.5 - x0*x0-y0*y0;
+ if(t0<0) n0 = 0.0;
+ else {
+ t0 *= t0;
+ n0 = t0 * t0 * dot(grad3[gi0], x0, y0); // (x,y) of grad3 used for 2D gradient
+ }
+ double t1 = 0.5 - x1*x1-y1*y1;
+ if(t1<0) n1 = 0.0;
+ else {
+ t1 *= t1;
+ n1 = t1 * t1 * dot(grad3[gi1], x1, y1);
+ }
+ double t2 = 0.5 - x2*x2-y2*y2;
+ if(t2<0) n2 = 0.0;
+ else {
+ t2 *= t2;
+ n2 = t2 * t2 * dot(grad3[gi2], x2, y2);
+ }
+ // Add contributions from each corner to get the final noise value.
+ // The result is scaled to return values in the interval [-1,1].
+ return 70.0 * (n0 + n1 + n2);
+ }
+
+
+ // 3D simplex noise
+ public double getValue(double xin, double yin, double zin) {
+ double n0, n1, n2, n3; // Noise contributions from the four corners
+ // Skew the input space to determine which simplex cell we're in
+ xin+=(seed + (seed * 7)) % Double.MAX_VALUE;
+ xin+=(seed + (seed * 13)) % Double.MAX_VALUE;
+ xin+=(seed + (seed * 17)) % Double.MAX_VALUE;
+ double s = (xin+yin+zin)*F3; // Very nice and simple skew factor for 3D
+ int i = fastfloor(xin+s);
+ int j = fastfloor(yin+s);
+ int k = fastfloor(zin+s);
+ double t = (i+j+k)*G3;
+ double X0 = i-t; // Unskew the cell origin back to (x,y,z) space
+ double Y0 = j-t;
+ double Z0 = k-t;
+ double x0 = xin-X0; // The x,y,z distances from the cell origin
+ double y0 = yin-Y0;
+ double z0 = zin-Z0;
+ // For the 3D case, the simplex shape is a slightly irregular tetrahedron.
+ // Determine which simplex we are in.
+ int i1, j1, k1; // Offsets for second corner of simplex in (i,j,k) coords
+ int i2, j2, k2; // Offsets for third corner of simplex in (i,j,k) coords
+ if(x0>=y0) {
+ if(y0>=z0)
+ { i1=1; j1=0; k1=0; i2=1; j2=1; k2=0; } // X Y Z order
+ else if(x0>=z0) { i1=1; j1=0; k1=0; i2=1; j2=0; k2=1; } // X Z Y order
+ else { i1=0; j1=0; k1=1; i2=1; j2=0; k2=1; } // Z X Y order
+ }
+ else { // x0<y0
+ if(y0<z0) { i1=0; j1=0; k1=1; i2=0; j2=1; k2=1; } // Z Y X order
+ else if(x0<z0) { i1=0; j1=1; k1=0; i2=0; j2=1; k2=1; } // Y Z X order
+ else { i1=0; j1=1; k1=0; i2=1; j2=1; k2=0; } // Y X Z order
+ }
+ // A step of (1,0,0) in (i,j,k) means a step of (1-c,-c,-c) in (x,y,z),
+ // a step of (0,1,0) in (i,j,k) means a step of (-c,1-c,-c) in (x,y,z), and
+ // a step of (0,0,1) in (i,j,k) means a step of (-c,-c,1-c) in (x,y,z), where
+ // c = 1/6.
+ double x1 = x0 - i1 + G3; // Offsets for second corner in (x,y,z) coords
+ double y1 = y0 - j1 + G3;
+ double z1 = z0 - k1 + G3;
+ double x2 = x0 - i2 + 2.0*G3; // Offsets for third corner in (x,y,z) coords
+ double y2 = y0 - j2 + 2.0*G3;
+ double z2 = z0 - k2 + 2.0*G3;
+ double x3 = x0 - 1.0 + 3.0*G3; // Offsets for last corner in (x,y,z) coords
+ double y3 = y0 - 1.0 + 3.0*G3;
+ double z3 = z0 - 1.0 + 3.0*G3;
+ // Work out the hashed gradient indices of the four simplex corners
+ int ii = i & 255;
+ int jj = j & 255;
+ int kk = k & 255;
+
+ int gi0 = permMod12[ii+perm[jj+perm[kk]]];
+ int gi1 = permMod12[ii+i1+perm[jj+j1+perm[kk+k1]]];
+ int gi2 = permMod12[ii+i2+perm[jj+j2+perm[kk+k2]]];
+ int gi3 = permMod12[ii+1+perm[jj+1+perm[kk+1]]];
+ // Calculate the contribution from the four corners
+ double t0 = 0.6 - x0*x0 - y0*y0 - z0*z0;
+ if(t0<0) n0 = 0.0;
+ else {
+ t0 *= t0;
+ n0 = t0 * t0 * dot(grad3[gi0], x0, y0, z0);
+ }
+ double t1 = 0.6 - x1*x1 - y1*y1 - z1*z1;
+ if(t1<0) n1 = 0.0;
+ else {
+ t1 *= t1;
+ n1 = t1 * t1 * dot(grad3[gi1], x1, y1, z1);
+ }
+ double t2 = 0.6 - x2*x2 - y2*y2 - z2*z2;
+ if(t2<0) n2 = 0.0;
+ else {
+ t2 *= t2;
+ n2 = t2 * t2 * dot(grad3[gi2], x2, y2, z2);
+ }
+ double t3 = 0.6 - x3*x3 - y3*y3 - z3*z3;
+ if(t3<0) n3 = 0.0;
+ else {
+ t3 *= t3;
+ n3 = t3 * t3 * dot(grad3[gi3], x3, y3, z3);
+ }
+ // Add contributions from each corner to get the final noise value.
+ // The result is scaled to stay just inside [-1,1]
+ return 32.0*(n0 + n1 + n2 + n3);
+ }
+
+
+ // 4D simplex noise, better simplex rank ordering method 2012-03-09
+ public double getValue4d(double x, double y, double z, double w) {
+
+ double n0, n1, n2, n3, n4; // Noise contributions from the five corners
+ // Skew the (x,y,z,w) space to determine which cell of 24 simplices we're in
+ double s = (x + y + z + w) * F4; // Factor for 4D skewing
+ int i = fastfloor(x + s);
+ int j = fastfloor(y + s);
+ int k = fastfloor(z + s);
+ int l = fastfloor(w + s);
+ double t = (i + j + k + l) * G4; // Factor for 4D unskewing
+ double X0 = i - t; // Unskew the cell origin back to (x,y,z,w) space
+ double Y0 = j - t;
+ double Z0 = k - t;
+ double W0 = l - t;
+ double x0 = x - X0; // The x,y,z,w distances from the cell origin
+ double y0 = y - Y0;
+ double z0 = z - Z0;
+ double w0 = w - W0;
+ // For the 4D case, the simplex is a 4D shape I won't even try to describe.
+ // To find out which of the 24 possible simplices we're in, we need to
+ // determine the magnitude ordering of x0, y0, z0 and w0.
+ // Six pair-wise comparisons are performed between each possible pair
+ // of the four coordinates, and the results are used to rank the numbers.
+ int rankx = 0;
+ int ranky = 0;
+ int rankz = 0;
+ int rankw = 0;
+ if(x0 > y0) rankx++; else ranky++;
+ if(x0 > z0) rankx++; else rankz++;
+ if(x0 > w0) rankx++; else rankw++;
+ if(y0 > z0) ranky++; else rankz++;
+ if(y0 > w0) ranky++; else rankw++;
+ if(z0 > w0) rankz++; else rankw++;
+ int i1, j1, k1, l1; // The integer offsets for the second simplex corner
+ int i2, j2, k2, l2; // The integer offsets for the third simplex corner
+ int i3, j3, k3, l3; // The integer offsets for the fourth simplex corner
+ // simplex[c] is a 4-vector with the numbers 0, 1, 2 and 3 in some order.
+ // Many values of c will never occur, since e.g. x>y>z>w makes x<z, y<w and x<w
+ // impossible. Only the 24 indices which have non-zero entries make any sense.
+ // We use a thresholding to set the coordinates in turn from the largest magnitude.
+ // Rank 3 denotes the largest coordinate.
+ i1 = rankx >= 3 ? 1 : 0;
+ j1 = ranky >= 3 ? 1 : 0;
+ k1 = rankz >= 3 ? 1 : 0;
+ l1 = rankw >= 3 ? 1 : 0;
+ // Rank 2 denotes the second largest coordinate.
+ i2 = rankx >= 2 ? 1 : 0;
+ j2 = ranky >= 2 ? 1 : 0;
+ k2 = rankz >= 2 ? 1 : 0;
+ l2 = rankw >= 2 ? 1 : 0;
+ // Rank 1 denotes the second smallest coordinate.
+ i3 = rankx >= 1 ? 1 : 0;
+ j3 = ranky >= 1 ? 1 : 0;
+ k3 = rankz >= 1 ? 1 : 0;
+ l3 = rankw >= 1 ? 1 : 0;
+ // The fifth corner has all coordinate offsets = 1, so no need to compute that.
+ double x1 = x0 - i1 + G4; // Offsets for second corner in (x,y,z,w) coords
+ double y1 = y0 - j1 + G4;
+ double z1 = z0 - k1 + G4;
+ double w1 = w0 - l1 + G4;
+ double x2 = x0 - i2 + 2.0*G4; // Offsets for third corner in (x,y,z,w) coords
+ double y2 = y0 - j2 + 2.0*G4;
+ double z2 = z0 - k2 + 2.0*G4;
+ double w2 = w0 - l2 + 2.0*G4;
+ double x3 = x0 - i3 + 3.0*G4; // Offsets for fourth corner in (x,y,z,w) coords
+ double y3 = y0 - j3 + 3.0*G4;
+ double z3 = z0 - k3 + 3.0*G4;
+ double w3 = w0 - l3 + 3.0*G4;
+ double x4 = x0 - 1.0 + 4.0*G4; // Offsets for last corner in (x,y,z,w) coords
+ double y4 = y0 - 1.0 + 4.0*G4;
+ double z4 = z0 - 1.0 + 4.0*G4;
+ double w4 = w0 - 1.0 + 4.0*G4;
+ // Work out the hashed gradient indices of the five simplex corners
+ int ii = i & 255;
+ int jj = j & 255;
+ int kk = k & 255;
+ int ll = l & 255;
+ int gi0 = perm[ii+perm[jj+perm[kk+perm[ll]]]] % 32;
+ int gi1 = perm[ii+i1+perm[jj+j1+perm[kk+k1+perm[ll+l1]]]] % 32;
+ int gi2 = perm[ii+i2+perm[jj+j2+perm[kk+k2+perm[ll+l2]]]] % 32;
+ int gi3 = perm[ii+i3+perm[jj+j3+perm[kk+k3+perm[ll+l3]]]] % 32;
+ int gi4 = perm[ii+1+perm[jj+1+perm[kk+1+perm[ll+1]]]] % 32;
+ // Calculate the contribution from the five corners
+ double t0 = 0.6 - x0*x0 - y0*y0 - z0*z0 - w0*w0;
+ if(t0<0) n0 = 0.0;
+ else {
+ t0 *= t0;
+ n0 = t0 * t0 * dot(grad4[gi0], x0, y0, z0, w0);
+ }
+ double t1 = 0.6 - x1*x1 - y1*y1 - z1*z1 - w1*w1;
+ if(t1<0) n1 = 0.0;
+ else {
+ t1 *= t1;
+ n1 = t1 * t1 * dot(grad4[gi1], x1, y1, z1, w1);
+ }
+ double t2 = 0.6 - x2*x2 - y2*y2 - z2*z2 - w2*w2;
+ if(t2<0) n2 = 0.0;
+ else {
+ t2 *= t2;
+ n2 = t2 * t2 * dot(grad4[gi2], x2, y2, z2, w2);
+ }
+ double t3 = 0.6 - x3*x3 - y3*y3 - z3*z3 - w3*w3;
+ if(t3<0) n3 = 0.0;
+ else {
+ t3 *= t3;
+ n3 = t3 * t3 * dot(grad4[gi3], x3, y3, z3, w3);
+ }
+ double t4 = 0.6 - x4*x4 - y4*y4 - z4*z4 - w4*w4;
+ if(t4<0) n4 = 0.0;
+ else {
+ t4 *= t4;
+ n4 = t4 * t4 * dot(grad4[gi4], x4, y4, z4, w4);
+ }
+ // Sum up and scale the result to cover the range [-1,1]
+ return 27.0 * (n0 + n1 + n2 + n3 + n4);
+ }
+
+ // Inner class to speed upp gradient computations
+ // (array access is a lot slower than member access)
+ private static class Grad
+ {
+ double x, y, z, w;
+
+ Grad(double x, double y, double z)
+ {
+ this.x = x;
+ this.y = y;
+ this.z = z;
+ }
+
+ Grad(double x, double y, double z, double w)
+ {
+ this.x = x;
+ this.y = y;
+ this.z = z;
+ this.w = w;
+ }
+ }
+}
diff --git a/src/libnoiseforjava/module/Spheres.java b/src/libnoiseforjava/module/Spheres.java new file mode 100644 index 0000000..03b580f --- /dev/null +++ b/src/libnoiseforjava/module/Spheres.java @@ -0,0 +1,102 @@ +/*
+ * Copyright (C) 2003, 2004 Jason Bevins (original libnoise code)
+ * Copyright 2010 Thomas J. Hodge (java port of libnoise)
+ *
+ * This file is part of libnoiseforjava.
+ *
+ * libnoiseforjava is a Java port of the C++ library libnoise, which may be found at
+ * http://libnoise.sourceforge.net/. libnoise was developed by Jason Bevins, who may be
+ * contacted at [email protected] (for great email, take off every 'zig').
+ * Porting to Java was done by Thomas Hodge, who may be contacted at
+ * [email protected] (remove every 'zag').
+ *
+ * libnoiseforjava is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * libnoiseforjava is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * libnoiseforjava. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package libnoiseforjava.module;
+
+public class Spheres extends ModuleBase
+{
+
+ /// Noise module that outputs concentric spheres.
+ ///
+ /// This noise module outputs concentric spheres centered on the origin
+ /// like the concentric rings of an onion.
+ ///
+ /// The first sphere has a radius of 1.0. Each subsequent sphere has a
+ /// radius that is 1.0 unit larger than the previous sphere.
+ ///
+ /// The output value from this noise module is determined by the distance
+ /// between the input value and the the nearest spherical surface. The
+ /// input values that are located on a spherical surface are given the
+ /// output value 1.0 and the input values that are equidistant from two
+ /// spherical surfaces are given the output value -1.0.
+ ///
+ /// An application can change the frequency of the concentric spheres.
+ /// Increasing the frequency reduces the distances between spheres. To
+ /// specify the frequency, call the setFrequency() method.
+ ///
+ /// This noise module, modified with some low-frequency, low-power
+ /// turbulence, is useful for generating agate-like textures.
+ ///
+ /// This noise module does not require any source modules.
+
+ /// Default frequency value for the Spheres noise module.
+ static final double DEFAULT_SPHERES_FREQUENCY = 1.0;
+
+ /// Frequency of the concentric spheres.
+ double frequency;
+
+
+ public Spheres ()
+ {
+ super(0);
+ frequency = DEFAULT_SPHERES_FREQUENCY;
+ }
+
+ public double getValue (double x, double y, double z)
+ {
+ x *= frequency;
+ y *= frequency;
+ z *= frequency;
+
+ double distFromCenter = Math.sqrt (x * x + y * y + z * z);
+ double distFromSmallerSphere = distFromCenter - Math.floor (distFromCenter);
+ double distFromLargerSphere = 1.0 - distFromSmallerSphere;
+ double nearestDist = Math.min(distFromSmallerSphere, distFromLargerSphere);
+ return 1.0 - (nearestDist * 4.0); // Puts it in the -1.0 to +1.0 range.
+ }
+
+ /// Returns the frequency of the concentric spheres.
+ ///
+ /// @returns The frequency of the concentric spheres.
+ ///
+ /// Increasing the frequency increases the density of the concentric
+ /// spheres, reducing the distances between them.
+ public double getFrequency ()
+ {
+ return frequency;
+ }
+
+ /// Sets the frequency of the concentric spheres.
+ ///
+ /// @param frequency The frequency of the concentric spheres.
+ ///
+ /// Increasing the frequency increases the density of the concentric
+ /// spheres, reducing the distances between them.
+ public void setFrequency (double frequency)
+ {
+ this.frequency = frequency;
+ }
+
+}
diff --git a/src/libnoiseforjava/module/Terrace.java b/src/libnoiseforjava/module/Terrace.java new file mode 100644 index 0000000..2c22733 --- /dev/null +++ b/src/libnoiseforjava/module/Terrace.java @@ -0,0 +1,326 @@ +/*
+ * Copyright (C) 2003, 2004 Jason Bevins (original libnoise code)
+ * Copyright 2010 Thomas J. Hodge (java port of libnoise)
+ *
+ * This file is part of libnoiseforjava.
+ *
+ * libnoiseforjava is a Java port of the C++ library libnoise, which may be found at
+ * http://libnoise.sourceforge.net/. libnoise was developed by Jason Bevins, who may be
+ * contacted at [email protected] (for great email, take off every 'zig').
+ * Porting to Java was done by Thomas Hodge, who may be contacted at
+ * [email protected] (remove every 'zag').
+ *
+ * libnoiseforjava is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * libnoiseforjava is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * libnoiseforjava. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package libnoiseforjava.module;
+
+import libnoiseforjava.Interp;
+import libnoiseforjava.Misc;
+import libnoiseforjava.exception.ExceptionInvalidParam;
+
+public class Terrace extends ModuleBase
+{
+
+ /// Noise module that maps the output value from a source module onto a
+ /// terrace-forming curve.
+ ///
+ /// This noise module maps the output value from the source module onto a
+ /// terrace-forming curve. The start of this curve has a slope of zero;
+ /// its slope then smoothly increases. This curve also contains
+ /// <i>control points</i> which resets the slope to zero at that point,
+ /// producing a "terracing" effect. Refer to the following illustration:
+ ///
+ /// @image html terrace.png
+ ///
+ /// To add a control point to this noise module, call the
+ /// addControlPoint() method.
+ ///
+ /// An application must add a minimum of two control points to the curve.
+ /// If this is not done, the getValue() method fails. The control points
+ /// can have any value, although no two control points can have the same
+ /// value. There is no limit to the number of control points that can be
+ /// added to the curve.
+ ///
+ /// This noise module clamps the output value from the source module if
+ /// that value is less than the value of the lowest control point or
+ /// greater than the value of the highest control point.
+ ///
+ /// This noise module is often used to generate terrain features such as
+ /// your stereotypical desert canyon.
+ ///
+ /// This noise module requires one source module.
+
+
+ /// Number of control points stored in this noise module.
+ int controlPointCount;
+
+ /// Determines if the terrace-forming curve between all control points
+ /// is inverted.
+ boolean invertTerraces;
+
+ /// Array that stores the control points.
+ double [] controlPoints;
+
+
+ public Terrace (ModuleBase sourceModule) throws ExceptionInvalidParam
+ {
+ super(1);
+ setSourceModule(0, sourceModule);
+ controlPointCount = 0;
+ invertTerraces = false;
+ controlPoints = new double [0];
+
+ }
+
+ /// Adds a control point to the terrace-forming curve.
+ ///
+ /// @param value The value of the control point to add.
+ ///
+ /// @pre No two control points have the same value.
+ ///
+ /// @throw ExceptionInvalidParam An invalid parameter was
+ /// specified; see the preconditions for more information.
+ ///
+ /// Two or more control points define the terrace-forming curve. The
+ /// start of this curve has a slope of zero; its slope then smoothly
+ /// increases. At the control points, its slope resets to zero.
+ ///
+ /// It does not matter which order these points are added.
+ public void addControlPoint (double value) throws ExceptionInvalidParam
+ {
+ // Find the insertion point for the new control point and insert the new
+ // point at that position. The control point array will remain sorted by
+ // value.
+ int insertionPos = findInsertionPos (value);
+ insertAtPos (insertionPos, value);
+ }
+
+
+ /// Deletes all the control points on the terrace-forming curve.
+ ///
+ /// @post All control points on the terrace-forming curve are deleted.
+ public void clearAllControlPoints ()
+ {
+ controlPoints = null;
+ controlPointCount = 0;
+ }
+
+ /// Determines the array index in which to insert the control point
+ /// into the internal control point array.
+ ///
+ /// @param value The value of the control point.
+ ///
+ /// @returns The array index in which to insert the control point.
+ ///
+ /// @pre No two control points have the same value.
+ ///
+ /// @throw ExceptionInvalidParam An invalid parameter was
+ /// specified; see the preconditions for more information.
+ ///
+ /// By inserting the control point at the returned array index, this
+ /// class ensures that the control point array is sorted by value.
+ /// The code that maps a value onto the curve requires a sorted
+ /// control point array.
+ public int findInsertionPos (double value) throws ExceptionInvalidParam
+ {
+ int insertionPos;
+ for (insertionPos = 0; insertionPos < controlPointCount; insertionPos++)
+ {
+ if (value < controlPoints[insertionPos])
+ // We found the array index in which to insert the new control point.
+ // Exit now.
+ break;
+ else if (value == controlPoints[insertionPos])
+ // Each control point is required to contain a unique value, so throw
+ // an exception.
+ throw new ExceptionInvalidParam ("Invalid Parameter in Terrace Noise Moduled");
+ }
+ return insertionPos;
+ }
+
+ public double getValue (double x, double y, double z)
+ {
+ assert (sourceModules[0] != null);
+ assert (controlPointCount >= 2);
+
+ // Get the output value from the source module.
+ double sourceModuleValue = sourceModules[0].getValue (x, y, z);
+
+ // Find the first element in the control point array that has a value
+ // larger than the output value from the source module.
+ int indexPos;
+ for (indexPos = 0; indexPos < controlPointCount; indexPos++)
+ {
+ if (sourceModuleValue < controlPoints[indexPos])
+ break;
+
+ }
+
+ // Find the two nearest control points so that we can map their values
+ // onto a quadratic curve.
+ int index0 = Misc.ClampValue (indexPos - 1, 0, controlPointCount - 1);
+ int index1 = Misc.ClampValue (indexPos, 0, controlPointCount - 1);
+
+ // If some control points are missing (which occurs if the output value from
+ // the source module is greater than the largest value or less than the
+ // smallest value of the control point array), get the value of the nearest
+ // control point and exit now.
+ if (index0 == index1)
+ return controlPoints[index1];
+
+ // Compute the alpha value used for linear interpolation.
+ double value0 = controlPoints[index0];
+ double value1 = controlPoints[index1];
+ double alpha = (sourceModuleValue - value0) / (value1 - value0);
+ if (invertTerraces)
+ {
+ alpha = 1.0 - alpha;
+ double tempValue = value0;
+ value0 = value1;
+ value1 = tempValue;
+ }
+
+ // Squaring the alpha produces the terrace effect.
+ alpha *= alpha;
+
+ // Now perform the linear interpolation given the alpha value.
+ return Interp.linearInterp (value0, value1, alpha);
+ }
+
+ /// Inserts the control point at the specified position in the
+ /// internal control point array.
+ ///
+ /// @param insertionPos The zero-based array position in which to
+ /// insert the control point.
+ /// @param value The value of the control point.
+ ///
+ /// To make room for this new control point, this method reallocates
+ /// the control point array and shifts all control points occurring
+ /// after the insertion position up by one.
+ ///
+ /// Because the curve mapping algorithm in this noise module requires
+ /// that all control points in the array be sorted by value, the new
+ /// control point should be inserted at the position in which the
+ /// order is still preserved.
+ public void insertAtPos (int insertionPos, double value)
+ {
+ // Make room for the new control point at the specified position within
+ // the control point array. The position is determined by the value of
+ // the control point; the control points must be sorted by value within
+ // that array.
+ double[] newControlPoints = new double[controlPointCount + 1];
+
+ for (int i = 0; i < controlPointCount; i++)
+ {
+ if (i < insertionPos)
+ newControlPoints[i] = controlPoints[i];
+ else
+ newControlPoints[i + 1] = controlPoints[i];
+ }
+
+ controlPoints = newControlPoints;
+ ++controlPointCount;
+
+ // Now that we've made room for the new control point within the array,
+ // add the new control point.
+ controlPoints[insertionPos] = value;
+ }
+
+ /// Creates a number of equally-spaced control points that range from
+ /// -1 to +1.
+ ///
+ /// @param controlPointCount The number of control points to generate.
+ ///
+ /// @pre The number of control points must be greater than or equal to
+ /// 2.
+ ///
+ /// @post The previous control points on the terrace-forming curve are
+ /// deleted.
+ ///
+ /// @throw ExceptionInvalidParam An invalid parameter was
+ /// specified; see the preconditions for more information.
+ ///
+ /// Two or more control points define the terrace-forming curve. The
+ /// start of this curve has a slope of zero; its slope then smoothly
+ /// increases. At the control points, its slope resets to zero.
+ void makeControlPoints (int controlPointCount) throws ExceptionInvalidParam
+ {
+ if (controlPointCount < 2)
+ throw new ExceptionInvalidParam ("Invalid Parameter in Terrace Noise Module");
+
+ clearAllControlPoints ();
+
+ double terraceStep = 2.0 / ((double)controlPointCount - 1.0);
+ double curValue = -1.0;
+ for (int i = 0; i < (int)controlPointCount; i++)
+ {
+ addControlPoint (curValue);
+ curValue += terraceStep;
+ }
+ }
+
+ /// Returns a pointer to the array of control points on the
+ /// terrace-forming curve.
+ ///
+ /// @returns A pointer to the array of control points in this noise
+ /// module.
+ ///
+ /// Two or more control points define the terrace-forming curve. The
+ /// start of this curve has a slope of zero; its slope then smoothly
+ /// increases. At the control points, its slope resets to zero.
+ ///
+ /// Before calling this method, call getControlPointCount() to
+ /// determine the number of control points in this array.
+ ///
+ /// It is recommended that an application does not store this pointer
+ /// for later use since the pointer to the array may change if the
+ /// application calls another method of this object.
+ public double[] getControlPointArray ()
+ {
+ return controlPoints;
+ }
+
+ /// Returns the number of control points on the terrace-forming curve.
+ ///
+ /// @returns The number of control points on the terrace-forming
+ /// curve.
+ public int getControlPointCount ()
+ {
+ return controlPointCount;
+ }
+
+ /// Enables or disables the inversion of the terrace-forming curve
+ /// between the control points.
+ ///
+ /// @param invert Specifies whether to invert the curve between the
+ /// control points.
+ public void invertTerraces (boolean invert)
+ {
+ if (invert)
+ invertTerraces = invert;
+ }
+
+ /// Determines if the terrace-forming curve between the control
+ /// points is inverted.
+ ///
+ /// @returns
+ /// - @a true if the curve between the control points is inverted.
+ /// - @a false if the curve between the control points is not
+ /// inverted.
+ public boolean isTerracesInverted ()
+ {
+ return invertTerraces;
+ }
+
+}
diff --git a/src/libnoiseforjava/module/TranslatePoint.java b/src/libnoiseforjava/module/TranslatePoint.java new file mode 100644 index 0000000..23ed712 --- /dev/null +++ b/src/libnoiseforjava/module/TranslatePoint.java @@ -0,0 +1,192 @@ +/*
+ * Copyright (C) 2003, 2004 Jason Bevins (original libnoise code)
+ * Copyright 2010 Thomas J. Hodge (java port of libnoise)
+ *
+ * This file is part of libnoiseforjava.
+ *
+ * libnoiseforjava is a Java port of the C++ library libnoise, which may be found at
+ * http://libnoise.sourceforge.net/. libnoise was developed by Jason Bevins, who may be
+ * contacted at [email protected] (for great email, take off every 'zig').
+ * Porting to Java was done by Thomas Hodge, who may be contacted at
+ * [email protected] (remove every 'zag').
+ *
+ * libnoiseforjava is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * libnoiseforjava is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * libnoiseforjava. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package libnoiseforjava.module;
+
+import libnoiseforjava.exception.ExceptionInvalidParam;
+
+public class TranslatePoint extends ModuleBase
+{
+ /// Noise module that moves the coordinates of the input value before
+ /// returning the output value from a source module.
+ ///
+ /// The getValue() method moves the ( @a x, @a y, @a z ) coordinates of
+ /// the input value by a translation amount before returning the output
+ /// value from the source module. To set the translation amount, call
+ /// the setTranslation() method. To set the translation amount to
+ /// apply to the individual @a x, @a y, or @a z coordinates, call the
+ /// setXTranslation(), setYTranslation() or setZTranslation() methods,
+ /// respectively.
+ ///
+ /// This noise module requires one source module.
+
+
+ /// Default translation factor applied to the @a x coordinate for the
+ /// TranslatePoint noise module.
+ static final double DEFAULT_TRANSLATE_POINT_X = 0.0;
+
+ /// Default translation factor applied to the @a y coordinate for the
+ /// TranslatePoint noise module.
+ static final double DEFAULT_TRANSLATE_POINT_Y = 0.0;
+
+ /// Default translation factor applied to the @a z coordinate for the
+ /// TranslatePoint noise module.
+ static final double DEFAULT_TRANSLATE_POINT_Z = 0.0;
+
+ /// Translation amount applied to the @a x coordinate of the input
+ /// value.
+ double xTranslation;
+
+ /// Translation amount applied to the @a y coordinate of the input
+ /// value.
+ double yTranslation;
+
+ /// Translation amount applied to the @a z coordinate of the input
+ /// value.
+ double zTranslation;
+
+ public TranslatePoint (ModuleBase sourceModule) throws ExceptionInvalidParam
+ {
+ super(1);
+ setSourceModule(0, sourceModule);
+ xTranslation = DEFAULT_TRANSLATE_POINT_X;
+ yTranslation = DEFAULT_TRANSLATE_POINT_Y;
+ zTranslation = DEFAULT_TRANSLATE_POINT_Z;
+
+ }
+
+ public double getValue (double x, double y, double z)
+ {
+ assert (sourceModules[0] != null);
+
+ return sourceModules[0].getValue (x + xTranslation, y + yTranslation,
+ z + zTranslation);
+ }
+
+ /// Returns the translation amount to apply to the @a x coordinate of
+ /// the input value.
+ ///
+ /// @returns The translation amount to apply to the @a x coordinate.
+ public double getXTranslation ()
+ {
+ return xTranslation;
+ }
+
+ /// Returns the translation amount to apply to the @a y coordinate of
+ /// the input value.
+ ///
+ /// @returns The translation amount to apply to the @a y coordinate.
+ public double getYTranslation ()
+ {
+ return yTranslation;
+ }
+
+ /// Returns the translation amount to apply to the @a z coordinate of
+ /// the input value.
+ ///
+ /// @returns The translation amount to apply to the @a z coordinate.
+ public double getZTranslation ()
+ {
+ return zTranslation;
+ }
+
+ /// Sets the translation amount to apply to the input value.
+ ///
+ /// @param translation The translation amount to apply.
+ ///
+ /// The getValue() method moves the ( @a x, @a y, @a z ) coordinates
+ /// of the input value by a translation amount before returning the
+ /// output value from the source module
+ public void setTranslation (double translation)
+ {
+ this.xTranslation = translation;
+ this.yTranslation = translation;
+ this.zTranslation = translation;
+ }
+
+ /// Sets the translation amounts to apply to the ( @a x, @a y, @a z )
+ /// coordinates of the input value.
+ ///
+ /// @param xTranslation The translation amount to apply to the @a x
+ /// coordinate.
+ /// @param yTranslation The translation amount to apply to the @a y
+ /// coordinate.
+ /// @param zTranslation The translation amount to apply to the @a z
+ /// coordinate.
+ ///
+ /// The getValue() method moves the ( @a x, @a y, @a z ) coordinates
+ /// of the input value by a translation amount before returning the
+ /// output value from the source module
+ public void setTranslation (double xTranslation, double yTranslation,
+ double zTranslation)
+ {
+ this.xTranslation = xTranslation;
+ this.yTranslation = yTranslation;
+ this.zTranslation = zTranslation;
+ }
+
+ /// Sets the translation amount to apply to the @a x coordinate of the
+ /// input value.
+ ///
+ /// @param xTranslation The translation amount to apply to the @a x
+ /// coordinate.
+ ///
+ /// The getValue() method moves the ( @a x, @a y, @a z ) coordinates
+ /// of the input value by a translation amount before returning the
+ /// output value from the source module
+ public void setXTranslation (double xTranslation)
+ {
+ this.xTranslation = xTranslation;
+ }
+
+ /// Sets the translation amount to apply to the @a y coordinate of the
+ /// input value.
+ ///
+ /// @param yTranslation The translation amount to apply to the @a y
+ /// coordinate.
+ ///
+ /// The getValue() method moves the ( @a x, @a y, @a z ) coordinates
+ /// of the input value by a translation amount before returning the
+ /// output value from the source module
+ public void setYTranslation (double yTranslation)
+ {
+ this.yTranslation = yTranslation;
+ }
+
+ /// Sets the translation amount to apply to the @a z coordinate of the
+ /// input value.
+ ///
+ /// @param zTranslation The translation amount to apply to the @a z
+ /// coordinate.
+ ///
+ /// The getValue() method moves the ( @a x, @a y, @a z ) coordinates
+ /// of the input value by a translation amount before returning the
+ /// output value from the source module
+ public void setZTranslation (double zTranslation)
+ {
+ this.zTranslation = zTranslation;
+ }
+
+}
diff --git a/src/libnoiseforjava/module/Turbulence.java b/src/libnoiseforjava/module/Turbulence.java new file mode 100644 index 0000000..021cff0 --- /dev/null +++ b/src/libnoiseforjava/module/Turbulence.java @@ -0,0 +1,282 @@ +/*
+ * Copyright (C) 2003, 2004 Jason Bevins (original libnoise code)
+ * Copyright 2010 Thomas J. Hodge (java port of libnoise)
+ *
+ * This file is part of libnoiseforjava.
+ *
+ * libnoiseforjava is a Java port of the C++ library libnoise, which may be found at
+ * http://libnoise.sourceforge.net/. libnoise was developed by Jason Bevins, who may be
+ * contacted at [email protected] (for great email, take off every 'zig').
+ * Porting to Java was done by Thomas Hodge, who may be contacted at
+ * [email protected] (remove every 'zag').
+ *
+ * libnoiseforjava is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * libnoiseforjava is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * libnoiseforjava. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package libnoiseforjava.module;
+
+import libnoiseforjava.exception.ExceptionInvalidParam;
+
+public class Turbulence extends ModuleBase
+{
+ /// Noise module that randomly displaces the input value before
+ /// returning the output value from a source module.
+ ///
+ /// @a Turbulence is the pseudo-random displacement of the input value.
+ /// The getValue() method randomly displaces the ( @a x, @a y, @a z )
+ /// coordinates of the input value before retrieving the output value from
+ /// the source module. To control the turbulence, an application can
+ /// modify its frequency, its power, and its roughness.
+ ///
+ /// The frequency of the turbulence determines how rapidly the
+ /// displacement amount changes. To specify the frequency, call the
+ /// setFrequency() method.
+ ///
+ /// The power of the turbulence determines the scaling factor that is
+ /// applied to the displacement amount. To specify the power, call the
+ /// setPower() method.
+ ///
+ /// The roughness of the turbulence determines the roughness of the
+ /// changes to the displacement amount. Low values smoothly change the
+ /// displacement amount. High values roughly change the displacement
+ /// amount, which produces more "kinky" changes. To specify the
+ /// roughness, call the setRoughness() method.
+ ///
+ /// Use of this noise module may require some trial and error. Assuming
+ /// that you are using a generator module as the source module, you
+ /// should first:
+ /// - Set the frequency to the same frequency as the source module.
+ /// - Set the power to the reciprocal of the frequency.
+ ///
+ /// From these initial frequency and power values, modify these values
+ /// until this noise module produce the desired changes in your terrain or
+ /// texture. For example:
+ /// - Low frequency (1/8 initial frequency) and low power (1/8 initial
+ /// power) produces very minor, almost unnoticeable changes.
+ /// - Low frequency (1/8 initial frequency) and high power (8 times
+ /// initial power) produces "ropey" lava-like terrain or marble-like
+ /// textures.
+ /// - High frequency (8 times initial frequency) and low power (1/8
+ /// initial power) produces a noisy version of the initial terrain or
+ /// texture.
+ /// - High frequency (8 times initial frequency) and high power (8 times
+ /// initial power) produces nearly pure noise, which isn't entirely
+ /// useful.
+ ///
+ /// Displacing the input values result in more realistic terrain and
+ /// textures. If you are generating elevations for terrain height maps,
+ /// you can use this noise module to produce more realistic mountain
+ /// ranges or terrain features that look like flowing lava rock. If you
+ /// are generating values for textures, you can use this noise module to
+ /// produce realistic marble-like or "oily" textures.
+ ///
+ /// Internally, there are three noise::module::Perlin noise modules
+ /// that displace the input value; one for the @a x, one for the @a y,
+ /// and one for the @a z coordinate.
+ ///
+ /// This noise module requires one source module.
+
+ /// Default frequency for the Turbulence noise module.
+ static final double DEFAULT_TURBULENCE_FREQUENCY = Perlin.DEFAULT_PERLIN_FREQUENCY;
+
+ /// Default power for the Turbulence noise module.
+ static final double DEFAULT_TURBULENCE_POWER = 1.0;
+
+ /// Default roughness for the Turbulence noise module.
+ static final int DEFAULT_TURBULENCE_ROUGHNESS = 3;
+
+ /// Default noise seed for the Turbulence noise module.
+ static final int DEFAULT_TURBULENCE_SEED = Perlin.DEFAULT_PERLIN_SEED;
+
+
+ /// The power (scale) of the displacement.
+ double power;
+
+ /// Noise module that displaces the @a x coordinate.
+ Perlin xDistortModule;
+
+ /// Noise module that displaces the @a y coordinate.
+ Perlin yDistortModule;
+
+ /// Noise module that displaces the @a z coordinate.
+ Perlin zDistortModule;
+
+ public Turbulence (ModuleBase sourceModule) throws ExceptionInvalidParam
+ {
+ super(1);
+ setSourceModule(0, sourceModule);
+
+ power = DEFAULT_TURBULENCE_POWER;
+
+ xDistortModule = new Perlin();
+ yDistortModule = new Perlin();
+ zDistortModule = new Perlin();
+
+ setSeed(DEFAULT_TURBULENCE_SEED);
+ setFrequency(DEFAULT_TURBULENCE_FREQUENCY);
+ setRoughness (DEFAULT_TURBULENCE_ROUGHNESS);
+ }
+
+ /// Returns the frequency of the turbulence.
+ ///
+ /// @returns The frequency of the turbulence.
+ ///
+ /// The frequency of the turbulence determines how rapidly the
+ /// displacement amount changes.
+ public double getFrequency ()
+ {
+ // Since each noise::module::Perlin noise module has the same frequency, it
+ // does not matter which module we use to retrieve the frequency.
+ return xDistortModule.getFrequency ();
+ }
+
+ /// Returns the seed value of the internal Perlin-noise modules that
+ /// are used to displace the input values.
+ ///
+ /// @returns The seed value.
+ ///
+ /// Internally, there are three Perlin noise modules
+ /// that displace the input value; one for the @a x, one for the @a y,
+ /// and one for the @a z coordinate.
+ public int getSeed ()
+ {
+ return xDistortModule.getSeed ();
+ }
+
+ public double getValue (double x, double y, double z)
+ {
+ assert (sourceModules[0] != null);
+
+ // Get the values from the three Perlin noise modules and
+ // add each value to each coordinate of the input value. There are also
+ // some offsets added to the coordinates of the input values. This prevents
+ // the distortion modules from returning zero if the (x, y, z) coordinates,
+ // when multiplied by the frequency, are near an integer boundary. This is
+ // due to a property of gradient coherent noise, which returns zero at
+ // integer boundaries.
+ double x0, y0, z0;
+ double x1, y1, z1;
+ double x2, y2, z2;
+
+ x0 = x + (12414.0 / 65536.0);
+ y0 = y + (65124.0 / 65536.0);
+ z0 = z + (31337.0 / 65536.0);
+ x1 = x + (26519.0 / 65536.0);
+ y1 = y + (18128.0 / 65536.0);
+ z1 = z + (60493.0 / 65536.0);
+ x2 = x + (53820.0 / 65536.0);
+ y2 = y + (11213.0 / 65536.0);
+ z2 = z + (44845.0 / 65536.0);
+
+ double xDistort = x + (xDistortModule.getValue (x0, y0, z0)
+ * power);
+ double yDistort = y + (yDistortModule.getValue (x1, y1, z1)
+ * power);
+ double zDistort = z + (zDistortModule.getValue (x2, y2, z2)
+ * power);
+
+ // Retrieve the output value at the offsetted input value instead of the
+ // original input value.
+ return sourceModules[0].getValue (xDistort, yDistort, zDistort);
+ }
+
+ /// Sets the seed value of the internal noise modules that are used to
+ /// displace the input values.
+ ///
+ /// @param seed The seed value.
+ ///
+ /// Internally, there are three Perlin noise modules
+ /// that displace the input value; one for the @a x, one for the @a y,
+ /// and one for the @a z coordinate. This noise module assigns the
+ /// following seed values to the Perlin noise modules:
+ /// - It assigns the seed value (@a seed + 0) to the @a x noise module.
+ /// - It assigns the seed value (@a seed + 1) to the @a y noise module.
+ /// - It assigns the seed value (@a seed + 2) to the @a z noise module.
+ /// This is done to prevent any sort of weird artifacting.
+ public void setSeed (int seed)
+ {
+ xDistortModule.setSeed (seed);
+ yDistortModule.setSeed (seed + 1);
+ zDistortModule.setSeed (seed + 2);
+ }
+
+ /// Returns the power of the turbulence.
+ ///
+ /// @returns The power of the turbulence.
+ ///
+ /// The power of the turbulence determines the scaling factor that is
+ /// applied to the displacement amount.
+ public double getPower ()
+ {
+ return power;
+ }
+
+ /// Returns the roughness of the turbulence.
+ ///
+ /// @returns The roughness of the turbulence.
+ ///
+ /// The roughness of the turbulence determines the roughness of the
+ /// changes to the displacement amount. Low values smoothly change
+ /// the displacement amount. High values roughly change the
+ /// displacement amount, which produces more "kinky" changes.
+ public int getRoughnessCount ()
+ {
+ return xDistortModule.getOctaveCount ();
+ }
+
+ /// Sets the frequency of the turbulence.
+ ///
+ /// @param frequency The frequency of the turbulence.
+ ///
+ /// The frequency of the turbulence determines how rapidly the
+ /// displacement amount changes.
+ public void setFrequency (double frequency)
+ {
+ xDistortModule.setFrequency (frequency);
+ yDistortModule.setFrequency (frequency);
+ zDistortModule.setFrequency (frequency);
+ }
+
+ /// Sets the power of the turbulence.
+ ///
+ /// @param power The power of the turbulence.
+ ///
+ /// The power of the turbulence determines the scaling factor that is
+ /// applied to the displacement amount.
+ public void setPower (double power)
+ {
+ this.power = power;
+ }
+
+ /// Sets the roughness of the turbulence.
+ ///
+ /// @param roughness The roughness of the turbulence.
+ ///
+ /// The roughness of the turbulence determines the roughness of the
+ /// changes to the displacement amount. Low values smoothly change
+ /// the displacement amount. High values roughly change the
+ /// displacement amount, which produces more "kinky" changes.
+ ///
+ /// Internally, there are three Perlin noise modules
+ /// that displace the input value; one for the @a x, one for the @a y,
+ /// and one for the @a z coordinate. The roughness value is equal to
+ /// the number of octaves used by the noise::module::Perlin noise
+ /// modules.
+ public void setRoughness (int roughness) throws ExceptionInvalidParam
+ {
+ xDistortModule.setOctaveCount (roughness);
+ yDistortModule.setOctaveCount (roughness);
+ zDistortModule.setOctaveCount (roughness);
+ }
+
+}
diff --git a/src/libnoiseforjava/module/Voronoi.java b/src/libnoiseforjava/module/Voronoi.java new file mode 100644 index 0000000..79776c1 --- /dev/null +++ b/src/libnoiseforjava/module/Voronoi.java @@ -0,0 +1,283 @@ +/*
+ * Copyright (C) 2003, 2004 Jason Bevins (original libnoise code)
+ * Copyright 2010 Thomas J. Hodge (java port of libnoise)
+ *
+ * This file is part of libnoiseforjava.
+ *
+ * libnoiseforjava is a Java port of the C++ library libnoise, which may be found at
+ * http://libnoise.sourceforge.net/. libnoise was developed by Jason Bevins, who may be
+ * contacted at [email protected] (for great email, take off every 'zig').
+ * Porting to Java was done by Thomas Hodge, who may be contacted at
+ * [email protected] (remove every 'zag').
+ *
+ * libnoiseforjava is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * libnoiseforjava is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * libnoiseforjava. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package libnoiseforjava.module;
+
+import libnoiseforjava.NoiseGen;
+
+public class Voronoi extends ModuleBase
+{
+
+ /// Noise module that outputs Voronoi cells.
+ ///
+ /// In mathematics, a <i>Voronoi cell</i> is a region containing all the
+ /// points that are closer to a specific <i>seed point</i> than to any
+ /// other seed point. These cells mesh with one another, producing
+ /// polygon-like formations.
+ ///
+ /// By default, this noise module randomly places a seed point within
+ /// each unit cube. By modifying the <i>frequency</i> of the seed points,
+ /// an application can change the distance between seed points. The
+ /// higher the frequency, the closer together this noise module places
+ /// the seed points, which reduces the size of the cells. To specify the
+ /// frequency of the cells, call the setFrequency() method.
+ ///
+ /// This noise module assigns each Voronoi cell with a random constant
+ /// value from a coherent-noise function. The <i>displacement value</i>
+ /// controls the range of random values to assign to each cell. The
+ /// range of random values is +/- the displacement value. Call the
+ /// setDisplacement() method to specify the displacement value.
+ ///
+ /// To modify the random positions of the seed points, call the SetSeed()
+ /// method.
+ ///
+ /// This noise module can optionally add the distance from the nearest
+ /// seed to the output value. To enable this feature, call the
+ /// enableDistance() method. This causes the points in the Voronoi cells
+ /// to increase in value the further away that point is from the nearest
+ /// seed point.
+ ///
+ /// Voronoi cells are often used to generate cracked-mud terrain
+ /// formations or crystal-like textures
+ ///
+ /// This noise module requires no source modules.
+
+
+ /// Default displacement to apply to each cell for the
+ /// Voronoi noise module.
+ final static double DEFAULT_VORONOI_DISPLACEMENT = 1.0;
+
+ /// Default frequency of the seed points for the Voronoi
+ /// noise module.
+ final static double DEFAULT_VORONOI_FREQUENCY = 1.0;
+
+ /// Default seed of the noise function for the Voronoi
+ /// noise module.
+ final static int DEFAULT_VORONOI_SEED = 0;
+
+ private static final double SQRT_3 = 1.7320508075688772935;
+
+
+ /// Scale of the random displacement to apply to each Voronoi cell.
+ double displacement;
+
+ /// Determines if the distance from the nearest seed point is applied to
+ /// the output value.
+ boolean enableDistance;
+
+ /// Frequency of the seed points.
+ double frequency;
+
+ /// Seed value used by the coherent-noise function to determine the
+ /// positions of the seed points.
+ int seed;
+
+
+ public Voronoi ()
+ {
+ super(0);
+ displacement = DEFAULT_VORONOI_DISPLACEMENT;
+ enableDistance = false;
+ frequency = DEFAULT_VORONOI_FREQUENCY;
+ seed = DEFAULT_VORONOI_SEED;
+ }
+
+ public double getValue (double x, double y, double z)
+ {
+ // This method could be more efficient by caching the seed values. Fix
+ // later.
+
+ x *= frequency;
+ y *= frequency;
+ z *= frequency;
+
+ int xInt = (x > 0.0? (int)x: (int)x - 1);
+ int yInt = (y > 0.0? (int)y: (int)y - 1);
+ int zInt = (z > 0.0? (int)z: (int)z - 1);
+
+ double minDist = 2147483647.0;
+ double xCandidate = 0;
+ double yCandidate = 0;
+ double zCandidate = 0;
+
+ // Inside each unit cube, there is a seed point at a random position. Go
+ // through each of the nearby cubes until we find a cube with a seed point
+ // that is closest to the specified position.
+ for (int zCur = zInt - 2; zCur <= zInt + 2; zCur++)
+ {
+ for (int yCur = yInt - 2; yCur <= yInt + 2; yCur++)
+ {
+ for (int xCur = xInt - 2; xCur <= xInt + 2; xCur++)
+ {
+ // Calculate the position and distance to the seed point inside of
+ // this unit cube.
+ double xPos = xCur + NoiseGen.ValueNoise3D (xCur, yCur, zCur, seed);
+ double yPos = yCur + NoiseGen.ValueNoise3D (xCur, yCur, zCur, seed + 1);
+ double zPos = zCur + NoiseGen.ValueNoise3D (xCur, yCur, zCur, seed + 2);
+ double xDist = xPos - x;
+ double yDist = yPos - y;
+ double zDist = zPos - z;
+ double dist = xDist * xDist + yDist * yDist + zDist * zDist;
+
+ if (dist < minDist)
+ {
+ // This seed point is closer to any others found so far, so record
+ // this seed point.
+ minDist = dist;
+ xCandidate = xPos;
+ yCandidate = yPos;
+ zCandidate = zPos;
+ }
+ }
+ }
+ }
+
+ double value;
+ if (enableDistance)
+ {
+ // Determine the distance to the nearest seed point.
+ double xDist = xCandidate - x;
+ double yDist = yCandidate - y;
+ double zDist = zCandidate - z;
+ value = (Math.sqrt(xDist * xDist + yDist * yDist + zDist * zDist)
+ ) * SQRT_3 - 1.0;
+ } else {
+ value = 0.0;
+ }
+
+ // Return the calculated distance with the displacement value applied.
+ return value + (displacement * (double)NoiseGen.ValueNoise3D (
+ (int)(Math.floor (xCandidate)),
+ (int)(Math.floor (yCandidate)),
+ (int)(Math.floor (zCandidate)), seed));// added seed here, not in original
+ // but there isn't a working method
+ // without seed
+ }
+
+ /// Enables or disables applying the distance from the nearest seed
+ /// point to the output value.
+ ///
+ /// @param enable Specifies whether to apply the distance to the
+ /// output value or not.
+ ///
+ /// Applying the distance from the nearest seed point to the output
+ /// value causes the points in the Voronoi cells to increase in value
+ /// the further away that point is from the nearest seed point.
+ /// Setting this value to @a true (and setting the displacement to a
+ /// near-zero value) causes this noise module to generate cracked mud
+ /// formations.
+ public void enableDistance (boolean enable)
+ {
+ enableDistance = enable;
+ }
+
+ /// Returns the displacement value of the Voronoi cells.
+ ///
+ /// @returns The displacement value of the Voronoi cells.
+ ///
+ /// This noise module assigns each Voronoi cell with a random constant
+ /// value from a coherent-noise function. The <i>displacement
+ /// value</i> controls the range of random values to assign to each
+ /// cell. The range of random values is +/- the displacement value.
+ public double getDisplacement ()
+ {
+ return displacement;
+ }
+
+ /// Returns the frequency of the seed points.
+ ///
+ /// @returns The frequency of the seed points.
+ ///
+ /// The frequency determines the size of the Voronoi cells and the
+ /// distance between these cells.
+ public double GetFrequency ()
+ {
+ return frequency;
+ }
+
+ /// Returns the seed value used by the Voronoi cells
+ ///
+ /// @returns The seed value.
+ ///
+ /// The positions of the seed values are calculated by a
+ /// coherent-noise function. By modifying the seed value, the output
+ /// of that function changes.
+ public int getSeed ()
+ {
+ return seed;
+ }
+
+ /// Determines if the distance from the nearest seed point is applied
+ /// to the output value.
+ ///
+ /// @returns
+ /// - @a true if the distance is applied to the output value.
+ /// - @a false if not.
+ ///
+ /// Applying the distance from the nearest seed point to the output
+ /// value causes the points in the Voronoi cells to increase in value
+ /// the further away that point is from the nearest seed point.
+ public boolean IsDistanceEnabled ()
+ {
+ return enableDistance;
+ }
+
+ /// Sets the displacement value of the Voronoi cells.
+ ///
+ /// @param displacement The displacement value of the Voronoi cells.
+ ///
+ /// This noise module assigns each Voronoi cell with a random constant
+ /// value from a coherent-noise function. The <i>displacement
+ /// value</i> controls the range of random values to assign to each
+ /// cell. The range of random values is +/- the displacement value.
+ public void setDisplacement (double displacement)
+ {
+ this.displacement = displacement;
+ }
+
+ /// Sets the frequency of the seed points.
+ ///
+ /// @param frequency The frequency of the seed points.
+ ///
+ /// The frequency determines the size of the Voronoi cells and the
+ /// distance between these cells.
+ public void setFrequency (double frequency)
+ {
+ this.frequency = frequency;
+ }
+
+ /// Sets the seed value used by the Voronoi cells
+ ///
+ /// @param seed The seed value.
+ ///
+ /// The positions of the seed values are calculated by a
+ /// coherent-noise function. By modifying the seed value, the output
+ /// of that function changes.
+ public void setSeed (int seed)
+ {
+ this.seed = seed;
+ }
+
+}
diff --git a/src/libnoiseforjava/util/ColorCafe.java b/src/libnoiseforjava/util/ColorCafe.java new file mode 100644 index 0000000..0b98471 --- /dev/null +++ b/src/libnoiseforjava/util/ColorCafe.java @@ -0,0 +1,105 @@ +/*
+ * Copyright (C) 2003, 2004 Jason Bevins (original libnoise code)
+ * Copyright 2010 Thomas J. Hodge (java port of libnoise)
+ *
+ * This file is part of libnoiseforjava.
+ *
+ * libnoiseforjava is a Java port of the C++ library libnoise, which may be found at
+ * http://libnoise.sourceforge.net/. libnoise was developed by Jason Bevins, who may be
+ * contacted at [email protected] (for great email, take off every 'zig').
+ * Porting to Java was done by Thomas Hodge, who may be contacted at
+ * [email protected] (remove every 'zag').
+ *
+ * libnoiseforjava is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * libnoiseforjava is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * libnoiseforjava. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package libnoiseforjava.util;
+
+public class ColorCafe
+{
+ /// Defines a color.
+ ///
+ /// A color object contains four 8-bit channels: red, green, blue, and an
+ /// alpha (transparency) channel. Channel values range from 0 to 255.
+ ///
+ /// The alpha channel defines the transparency of the color. If the alpha
+ /// channel has a value of 0, the color is completely transparent. If the
+ /// alpha channel has a value of 255, the color is completely opaque.
+
+ /// Value of the alpha (transparency) channel.
+ int alpha;
+
+ /// Value of the blue channel.
+ int blue;
+
+ /// Value of the green channel.
+ int green;
+
+ /// Value of the red channel.
+ int red;
+
+ /// Constructor.
+ ///
+ /// @param r Value of the red channel.
+ /// @param g Value of the green channel.
+ /// @param b Value of the blue channel.
+ /// @param a Value of the alpha (transparency) channel.
+ public ColorCafe (int red, int green, int blue, int alpha)
+ {
+ this.red = red;
+ this.blue = blue;
+ this.green = green;
+ this.alpha = alpha;
+ }
+
+ public int getAlpha()
+ {
+ return alpha;
+ }
+
+ public int getBlue()
+ {
+ return blue;
+ }
+
+ public int getGreen()
+ {
+ return green;
+ }
+
+ public int getRed()
+ {
+ return red;
+ }
+
+ public void setAlpha(int alpha)
+ {
+ this.alpha = alpha;
+ }
+
+ public void setBlue(int blue)
+ {
+ this.blue = blue;
+ }
+
+ public void setGreen(int green)
+ {
+ this.green = green;
+ }
+
+ public void setRed(int red)
+ {
+ this.red = red;
+ }
+
+}
diff --git a/src/libnoiseforjava/util/GradientColor.java b/src/libnoiseforjava/util/GradientColor.java new file mode 100644 index 0000000..ee241f4 --- /dev/null +++ b/src/libnoiseforjava/util/GradientColor.java @@ -0,0 +1,251 @@ +/*
+ * Copyright (C) 2003, 2004 Jason Bevins (original libnoise code)
+ * Copyright 2010 Thomas J. Hodge (java port of libnoise)
+ *
+ * This file is part of libnoiseforjava.
+ *
+ * libnoiseforjava is a Java port of the C++ library libnoise, which may be found at
+ * http://libnoise.sourceforge.net/. libnoise was developed by Jason Bevins, who may be
+ * contacted at [email protected] (for great email, take off every 'zig').
+ * Porting to Java was done by Thomas Hodge, who may be contacted at
+ * [email protected] (remove every 'zag').
+ *
+ * libnoiseforjava is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * libnoiseforjava is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * libnoiseforjava. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package libnoiseforjava.util;
+
+import libnoiseforjava.Misc;
+import libnoiseforjava.exception.ExceptionInvalidParam;
+
+public class GradientColor
+{
+ /// Defines a color gradient.
+ ///
+ /// A color gradient is a list of gradually-changing colors. A color
+ /// gradient is defined by a list of <i>gradient points</i>. Each
+ /// gradient point has a position and a color. In a color gradient, the
+ /// colors between two adjacent gradient points are linearly interpolated.
+ ///
+ /// To add a gradient point to the color gradient, pass its position and
+ /// color to the addGradientPoint() method.
+ ///
+ /// To retrieve a color from a specific position in the color gradient,
+ /// pass that position to the getColor() method.
+ ///
+ /// This class is a useful tool for coloring height maps based on
+ /// elevation.
+ ///
+ /// <b>Gradient example</b>
+ ///
+ /// Suppose a gradient object contains the following gradient points:
+ /// - -1.0 maps to black.
+ /// - 0.0 maps to white.
+ /// - 1.0 maps to red.
+ ///
+ /// If an application passes -0.5 to the getColor() method, this method
+ /// will return a gray color that is halfway between black and white.
+ ///
+ /// If an application passes 0.25 to the getColor() method, this method
+ /// will return a very light pink color that is one quarter of the way
+ /// between white and red.
+
+
+ GradientPoint [] gradientPoints;
+ int gradientPointCount;
+ ColorCafe workingColor;
+
+ public GradientColor()
+ {
+ gradientPoints = new GradientPoint[1];
+ gradientPoints[0] = new GradientPoint(0.0, new ColorCafe(0, 0, 0, 0));
+ }
+
+ /// Adds a gradient point to this gradient object.
+ ///
+ /// @param gradientPos The position of this gradient point.
+ /// @param gradientColor The color of this gradient point.
+ ///
+ /// @pre No two gradient points have the same position.
+ ///
+ /// @throw noise::ExceptionInvalidParam See the precondition.
+ ///
+ /// It does not matter which order these gradient points are added.
+ public void addGradientPoint (double gradientPos, ColorCafe gradientColor) throws ExceptionInvalidParam
+ {
+ // Find the insertion point for the new gradient point and insert the new
+ // gradient point at that insertion point. The gradient point array will
+ // remain sorted by gradient position.
+ int insertionPos = findInsertionPos (gradientPos);
+ insertAtPos (insertionPos, gradientPos, gradientColor);
+ }
+
+ /// Deletes all the gradient points from this gradient object.
+ ///
+ /// @post All gradient points from this gradient object are deleted.
+ public void clear ()
+ {
+ gradientPoints = null;
+ gradientPointCount = 0;
+ }
+
+ /// Determines the array index in which to insert the gradient point
+ /// into the internal gradient-point array.
+ ///
+ /// @param gradientPos The position of this gradient point.
+ ///
+ /// @returns The array index in which to insert the gradient point.
+ ///
+ /// @pre No two gradient points have the same input value.
+ ///
+ /// @throw noise::ExceptionInvalidParam See the precondition.
+ ///
+ /// By inserting the gradient point at the returned array index, this
+ /// object ensures that the gradient-point array is sorted by input
+ /// value. The code that maps a value to a color requires a sorted
+ /// gradient-point array.
+ public int findInsertionPos (double gradientPos) throws ExceptionInvalidParam
+ {
+ int insertionPos;
+ for (insertionPos = 0; insertionPos < gradientPointCount;
+ insertionPos++) {
+ if (gradientPos < gradientPoints[insertionPos].position) {
+ // We found the array index in which to insert the new gradient point.
+ // Exit now.
+ break;
+ } else if (gradientPos == gradientPoints[insertionPos].position) {
+ // Each gradient point is required to contain a unique gradient
+ // position, so throw an exception.
+ throw new ExceptionInvalidParam ("Invalid Parameter in Gradient Color");
+ }
+ }
+ return insertionPos;
+ }
+
+ /// Returns the color at the specified position in the color gradient.
+ ///
+ /// @param gradientPos The specified position.
+ ///
+ /// @returns The color at that position.
+ public ColorCafe getColor (double gradientPos)
+ {
+ assert (gradientPointCount >= 2);
+
+ // Find the first element in the gradient point array that has a gradient
+ // position larger than the gradient position passed to this method.
+ int indexPos;
+ for (indexPos = 0; indexPos < gradientPointCount; indexPos++)
+ {
+ if (gradientPos < gradientPoints[indexPos].position)
+ break;
+ }
+
+ // Find the two nearest gradient points so that we can perform linear
+ // interpolation on the color.
+ int index0 = Misc.ClampValue (indexPos - 1, 0, gradientPointCount - 1);
+ int index1 = Misc.ClampValue (indexPos, 0, gradientPointCount - 1);
+
+ // If some gradient points are missing (which occurs if the gradient
+ // position passed to this method is greater than the largest gradient
+ // position or less than the smallest gradient position in the array), get
+ // the corresponding gradient color of the nearest gradient point and exit
+ // now.
+ if (index0 == index1)
+ {
+ workingColor = gradientPoints[index1].color;
+ return workingColor;
+ }
+
+ // Compute the alpha value used for linear interpolation.
+ double input0 = gradientPoints[index0].position;
+ double input1 = gradientPoints[index1].position;
+ double alpha = (gradientPos - input0) / (input1 - input0);
+
+ // Now perform the linear interpolation given the alpha value.
+ ColorCafe color0 = gradientPoints[index0].color;
+ ColorCafe color1 = gradientPoints[index1].color;
+ workingColor = MiscUtilities.linearInterpColor (color0, color1, (float)alpha);
+ return workingColor;
+ }
+
+ /// Inserts the gradient point at the specified position in the
+ /// internal gradient-point array.
+ ///
+ /// @param insertionPos The zero-based array position in which to
+ /// insert the gradient point.
+ /// @param gradientPos The position of this gradient point.
+ /// @param gradientColor The color of this gradient point.
+ ///
+ /// To make room for this new gradient point, this method reallocates
+ /// the gradient-point array and shifts all gradient points occurring
+ /// after the insertion position up by one.
+ ///
+ /// Because this object requires that all gradient points in the array
+ /// must be sorted by the position, the new gradient point should be
+ /// inserted at the position in which the order is still preserved.
+ public void insertAtPos (int insertionPos, double gradientPos,
+ ColorCafe gradientColor)
+ {
+ // Make room for the new gradient point at the specified insertion position
+ // within the gradient point array. The insertion position is determined by
+ // the gradient point's position; the gradient points must be sorted by
+ // gradient position within that array.
+ GradientPoint [] newGradientPoints;
+ newGradientPoints = new GradientPoint[gradientPointCount + 1];
+
+ for (int t = 0; t < (gradientPointCount + 1); t++)
+ newGradientPoints[t] = new GradientPoint();
+
+
+
+ for (int i = 0; i < gradientPointCount; i++)
+ {
+ if (i < insertionPos)
+ newGradientPoints[i] = gradientPoints[i];
+ else
+ newGradientPoints[i + 1] = gradientPoints[i];
+ }
+
+ gradientPoints = newGradientPoints;
+ ++gradientPointCount;
+
+ // Now that we've made room for the new gradient point within the array, add
+ // the new gradient point.
+ gradientPoints[insertionPos].position = gradientPos;
+ gradientPoints[insertionPos].color = gradientColor;
+ }
+
+ /// Returns a pointer to the array of gradient points in this object.
+ ///
+ /// @returns A pointer to the array of gradient points.
+ ///
+ /// Before calling this method, call getGradientPointCount() to
+ /// determine the number of gradient points in this array.
+ ///
+ /// It is recommended that an application does not store this pointer
+ /// for later use since the pointer to the array may change if the
+ /// application calls another method of this object.
+ public GradientPoint[] getGradientPointArray ()
+ {
+ return gradientPoints;
+ }
+
+ /// Returns the number of gradient points stored in this object.
+ ///
+ /// @returns The number of gradient points stored in this object.
+ public int getGradientPointCount ()
+ {
+ return gradientPointCount;
+ }
+
+}
diff --git a/src/libnoiseforjava/util/GradientPoint.java b/src/libnoiseforjava/util/GradientPoint.java new file mode 100644 index 0000000..b48dab6 --- /dev/null +++ b/src/libnoiseforjava/util/GradientPoint.java @@ -0,0 +1,74 @@ +/*
+ * Copyright (C) 2003, 2004 Jason Bevins (original libnoise code)
+ * Copyright 2010 Thomas J. Hodge (java port of libnoise)
+ *
+ * This file is part of libnoiseforjava.
+ *
+ * libnoiseforjava is a Java port of the C++ library libnoise, which may be found at
+ * http://libnoise.sourceforge.net/. libnoise was developed by Jason Bevins, who may be
+ * contacted at [email protected] (for great email, take off every 'zig').
+ * Porting to Java was done by Thomas Hodge, who may be contacted at
+ * [email protected] (remove every 'zag').
+ *
+ * libnoiseforjava is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * libnoiseforjava is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * libnoiseforjava. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package libnoiseforjava.util;
+
+public class GradientPoint
+{
+ /// Defines a point used to build a color gradient.
+ ///
+ /// A color gradient is a list of gradually-changing colors. A color
+ /// gradient is defined by a list of <i>gradient points</i>. Each
+ /// gradient point has a position and a color. In a color gradient, the
+ /// colors between two adjacent gradient points are linearly interpolated.
+ ///
+ /// The ColorGradient class defines a color gradient by a list of these
+ /// objects.
+
+ double position;
+ ColorCafe color;
+
+ public GradientPoint()
+ {
+ position = 0.0;
+ color = new ColorCafe(0,0,0,0);
+ }
+
+ public GradientPoint(double position, ColorCafe color)
+ {
+ this.position = position;
+ this.color = color;
+ }
+
+ public double getPosition()
+ {
+ return position;
+ }
+
+ public ColorCafe getColor()
+ {
+ return color;
+ }
+
+ public void setPosition(double position)
+ {
+ this.position = position;
+ }
+
+ public void setColor(ColorCafe color)
+ {
+ this.color = color;
+ }
+}
diff --git a/src/libnoiseforjava/util/ImageCafe.java b/src/libnoiseforjava/util/ImageCafe.java new file mode 100644 index 0000000..746e700 --- /dev/null +++ b/src/libnoiseforjava/util/ImageCafe.java @@ -0,0 +1,173 @@ +/*
+ * Copyright (C) 2003, 2004 Jason Bevins (original libnoise code)
+ * Copyright 2010 Thomas J. Hodge (java port of libnoise)
+ *
+ * This file is part of libnoiseforjava.
+ *
+ * libnoiseforjava is a Java port of the C++ library libnoise, which may be found at
+ * http://libnoise.sourceforge.net/. libnoise was developed by Jason Bevins, who may be
+ * contacted at [email protected] (for great email, take off every 'zig').
+ * Porting to Java was done by Thomas Hodge, who may be contacted at
+ * [email protected] (remove every 'zag').
+ *
+ * libnoiseforjava is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * libnoiseforjava is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * libnoiseforjava. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package libnoiseforjava.util;
+
+import libnoiseforjava.exception.ExceptionInvalidParam;
+
+public class ImageCafe
+{
+
+ /// Implements an image, a 2-dimensional array of color values.
+ ///
+ /// An image can be used to store a color texture.
+ ///
+ /// These color values are of type ColorCafe.
+ ///
+ /// The size (width and height) of the image can be specified during
+ /// object construction.
+ ///
+ /// The getValue() and setValue() methods can be used to access individual
+ /// color values stored in the image.
+ ///
+ ///
+ /// <b>Border Values</b>
+ ///
+ /// All of the color values outside of the image are assumed to have a
+ /// common color value known as the <i>border value</i>.
+ ///
+ /// To set the border value, call the setBorderValue() method.
+ ///
+ /// The getValue() method returns the border value if the specified
+ /// position lies outside of the image.
+ ///
+
+ /// The Color value used for all positions outside of the image.
+ ColorCafe borderValue;
+
+ /// The current height of the image.
+ int height;
+
+ /// The current width of the image.
+ int width;
+
+ /// Array of ColorCafes holding the color values
+ ColorCafe [][] imageCafeColors;
+
+ public ImageCafe (int width, int height) throws ExceptionInvalidParam
+ {
+ setSize (width, height);
+ borderValue = new ColorCafe (0, 0, 0, 0);
+ imageCafeColors = new ColorCafe[width][height];
+ }
+
+ /// Returns a color value from the specified position in the image.
+ ///
+ /// @param x The x coordinate of the position.
+ /// @param y The y coordinate of the position.
+ ///
+ /// @returns The color value at that position.
+ ///
+ /// This method returns the border value if the coordinates exist
+ /// outside of the image.
+ public ColorCafe getValue (int x, int y)
+ {
+ if (x >= 0 && x < width && y >= 0 && y < height)
+ return imageCafeColors[x][y];
+ else
+ // The coordinates specified are outside the image. Return the border
+ // value.
+ return borderValue;
+ }
+
+ /// Sets the new size for the image.
+ ///
+ /// @param width The new width for the image.
+ /// @param height The new height for the image.
+ ///
+ /// @pre The width and height values are positive.
+ /// @pre The width and height values do not exceed the maximum
+ /// possible width and height for the image.
+ ///
+ /// @throw ExceptionInvalidParam See the preconditions.
+ public void setSize (int width, int height) throws ExceptionInvalidParam
+ {
+ if (width < 0 || height < 0)
+ // Invalid width or height.
+ throw new ExceptionInvalidParam ("Invalid Parameter in ImageCafe");
+ else
+ {
+ this.width = width;
+ this.height = height;
+ }
+ }
+
+ /// Sets a color value at a specified position in the image.
+ ///
+ /// @param x The x coordinate of the position.
+ /// @param y The y coordinate of the position.
+ /// @param value The color value to set at the given position.
+ ///
+ /// This method does nothing if the image is empty or the position is
+ /// outside the bounds of the image.
+ public void setValue (int x, int y, ColorCafe value)
+ {
+ if (x >= 0 && x < width && y >= 0 && y < height)
+ this.imageCafeColors[x][y] = value;
+ }
+
+
+ /// Returns the color value used for all positions outside of the
+ /// image.
+ ///
+ /// @returns The color value used for all positions outside of the
+ /// image.
+ ///
+ /// All positions outside of the image are assumed to have a common
+ /// color value known as the <i>border value</i>.
+ public ColorCafe getBorderValue ()
+ {
+ return borderValue;
+ }
+
+ /// Returns the height of the image.
+ ///
+ /// @returns The height of the image.
+ public int getHeight ()
+ {
+ return height;
+ }
+
+ /// Returns the width of the image.
+ ///
+ /// @returns The width of the image.
+ public int getWidth ()
+ {
+ return width;
+ }
+
+ /// Sets the color value to use for all positions outside of the
+ /// image.
+ ///
+ /// @param borderValue The color value to use for all positions
+ /// outside of the image.
+ ///
+ /// All positions outside of the image are assumed to have a common
+ /// color value known as the <i>border value</i>.
+ public void setBorderValue (ColorCafe borderValue)
+ {
+ this.borderValue = borderValue;
+ }
+}
diff --git a/src/libnoiseforjava/util/MiscUtilities.java b/src/libnoiseforjava/util/MiscUtilities.java new file mode 100644 index 0000000..a18aa6b --- /dev/null +++ b/src/libnoiseforjava/util/MiscUtilities.java @@ -0,0 +1,52 @@ +/*
+ * Copyright (C) 2003, 2004 Jason Bevins (original libnoise code)
+ * Copyright 2010 Thomas J. Hodge (java port of libnoise)
+ *
+ * This file is part of libnoiseforjava.
+ *
+ * libnoiseforjava is a Java port of the C++ library libnoise, which may be found at
+ * http://libnoise.sourceforge.net/. libnoise was developed by Jason Bevins, who may be
+ * contacted at [email protected] (for great email, take off every 'zig').
+ * Porting to Java was done by Thomas Hodge, who may be contacted at
+ * [email protected] (remove every 'zag').
+ *
+ * libnoiseforjava is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * libnoiseforjava is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * libnoiseforjava. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package libnoiseforjava.util;
+
+public class MiscUtilities
+{
+
+ // Performs linear interpolation between two 8-bit channel values.
+ public static short blendChannel (int red, int red2, float alpha)
+ {
+ double c0 = (float)red / 255.0;
+ double c1 = (float)red2 / 255.0;
+ return (short)(((c1 * alpha) + (c0 * (1.0f - alpha))) * 255.0f);
+ }
+
+ // Performs linear interpolation between two colors
+ public static ColorCafe linearInterpColor (ColorCafe color0, ColorCafe color1,
+ float alpha)
+ {
+ ColorCafe color = new ColorCafe(
+ blendChannel (color0.red, color1.red, alpha),
+ blendChannel (color0.green, color1.green, alpha),
+ blendChannel (color0.blue, color1.blue, alpha),
+ blendChannel (color0.alpha, color1.alpha, alpha)
+ );
+ return color;
+ }
+
+}
diff --git a/src/libnoiseforjava/util/NoiseMap.java b/src/libnoiseforjava/util/NoiseMap.java new file mode 100644 index 0000000..b0636f2 --- /dev/null +++ b/src/libnoiseforjava/util/NoiseMap.java @@ -0,0 +1,158 @@ +/*
+ * Copyright (C) 2003, 2004 Jason Bevins (original libnoise code)
+ * Copyright 2010 Thomas J. Hodge (java port of libnoise)
+ *
+ * This file is part of libnoiseforjava.
+ *
+ * libnoiseforjava is a Java port of the C++ library libnoise, which may be found at
+ * http://libnoise.sourceforge.net/. libnoise was developed by Jason Bevins, who may be
+ * contacted at [email protected] (for great email, take off every 'zig').
+ * Porting to Java was done by Thomas Hodge, who may be contacted at
+ * [email protected] (remove every 'zag').
+ *
+ * libnoiseforjava is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * libnoiseforjava is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * libnoiseforjava. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package libnoiseforjava.util;
+
+import libnoiseforjava.exception.ExceptionInvalidParam;
+
+public class NoiseMap
+{
+ /// Implements a noise map, a 2-dimensional array of floating-point
+ /// values.
+ ///
+ /// A noise map is designed to store coherent-noise values generated by a
+ /// noise module, although it can store values from any source. A noise
+ /// map is often used as a terrain height map or a grayscale texture.
+ ///
+ /// The size (width and height) of the noise map can be specified during
+ /// object construction.
+ ///
+ /// The getValue() method can be used to access individual
+ /// values stored in the noise map.
+ ///
+
+
+ /// The height of the noise map.
+ int height;
+
+ /// The width of the noise map.
+ int width;
+
+ /// The array of doubles holding the noise map values
+ double[][] noiseMap;
+
+ double borderValue;
+
+ public NoiseMap (int width, int height) throws ExceptionInvalidParam
+ {
+ setSize (width, height);
+ noiseMap = new double [width][height];
+ borderValue = 0.0;
+ }
+
+ /// Returns a value from the specified position in the noise map.
+ ///
+ /// @param x The x coordinate of the position.
+ /// @param y The y coordinate of the position.
+ ///
+ /// @returns The value at that position.
+ ///
+ /// This method returns the border value if the coordinates exist
+ /// outside of the noise map.
+ public double getValue (int x, int y)
+ {
+ if (x >= 0 && x < width && y >= 0 && y < height)
+ return noiseMap[x] [y];
+ // The coordinates specified are outside the noise map. Return the border
+ // value.
+ else
+ return borderValue;
+ }
+
+ public void setSize (int width, int height) throws ExceptionInvalidParam
+ {
+ if (width < 1 || height < 1)
+ // Invalid width or height.
+ throw new ExceptionInvalidParam ("Invalid parameter in NoiseMap");
+ else
+ {
+ this.width = width;
+ this.height = height;
+ }
+ }
+
+ /// Sets a value at a specified position in the noise map.
+ ///
+ /// @param x The x coordinate of the position.
+ /// @param y The y coordinate of the position.
+ /// @param value The value to set at the given position.
+ ///
+ /// This method does nothing if the noise map object is empty or the
+ /// position is outside the bounds of the noise map.
+ public void setValue (int x, int y, double value)
+ {
+ if (x >= 0 && x < width && y >= 0 && y < height)
+ this.noiseMap[x][y]= value;
+ }
+
+ /// Returns the value used for all positions outside of the noise map.
+ ///
+ /// @returns The value used for all positions outside of the noise
+ /// map.
+ ///
+ /// All positions outside of the noise map are assumed to have a
+ /// common value known as the <i>border value</i>.
+ public double getBorderValue ()
+ {
+ return borderValue;
+ }
+
+ /// Returns the height of the noise map.
+ ///
+ /// @returns The height of the noise map.
+ public int getHeight ()
+ {
+ return height;
+ }
+
+ /// Returns the width of the noise map.
+ ///
+ /// @returns The width of the noise map.
+ public int getWidth ()
+ {
+ return width;
+ }
+
+ /// Sets the value to use for all positions outside of the noise map.
+ ///
+ /// @param borderValue The value to use for all positions outside of
+ /// the noise map.
+ ///
+ /// All positions outside of the noise map are assumed to have a
+ /// common value known as the <i>border value</i>.
+ public void setBorderValue (double borderValue)
+ {
+ this.borderValue = borderValue;
+ }
+
+ public double[][] getNoiseMap() {
+ return noiseMap;
+ }
+
+ public void setNoiseMap(double[][] noiseMap) {
+ this.noiseMap = noiseMap;
+ }
+
+}
diff --git a/src/libnoiseforjava/util/NoiseMapBuilder.java b/src/libnoiseforjava/util/NoiseMapBuilder.java new file mode 100644 index 0000000..a091226 --- /dev/null +++ b/src/libnoiseforjava/util/NoiseMapBuilder.java @@ -0,0 +1,195 @@ +/*
+ * Copyright (C) 2003, 2004 Jason Bevins (original libnoise code)
+ * Copyright 2010 Thomas J. Hodge (java port of libnoise)
+ *
+ * This file is part of libnoiseforjava.
+ *
+ * libnoiseforjava is a Java port of the C++ library libnoise, which may be found at
+ * http://libnoise.sourceforge.net/. libnoise was developed by Jason Bevins, who may be
+ * contacted at [email protected] (for great email, take off every 'zig').
+ * Porting to Java was done by Thomas Hodge, who may be contacted at
+ * [email protected] (remove every 'zag').
+ *
+ * libnoiseforjava is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * libnoiseforjava is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * libnoiseforjava. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package libnoiseforjava.util;
+
+import libnoiseforjava.exception.ExceptionInvalidParam;
+import libnoiseforjava.module.ModuleBase;
+
+public class NoiseMapBuilder
+{
+
+ /// Base class for a noise-map builder
+ ///
+ /// A builder class builds a noise map by filling it with coherent-noise
+ /// values generated from the surface of a three-dimensional mathematical
+ /// object. Each builder class defines a specific three-dimensional
+ /// surface, such as a cylinder, sphere, or plane.
+ ///
+ /// A builder class describes these input values using a coordinate system
+ /// applicable for the mathematical object (e.g., a latitude/longitude
+ /// coordinate system for the spherical noise-map builder.) It then
+ /// "flattens" these coordinates onto a plane so that it can write the
+ /// coherent-noise values into a two-dimensional noise map.
+ ///
+ /// <b>Building the Noise Map</b>
+ ///
+ /// To build the noise map, perform the following steps:
+ /// - Pass the bounding coordinates to the setBounds() method.
+ /// - Pass the noise map size, in points, to the setDestSize() method.
+ /// - Pass a NoiseMap object to the setDestNoiseMap() method.
+ /// - Pass a noise module (derived from ModuleBase) to the
+ /// setSourceModule() method.
+ /// - Call the build() method.
+ ///
+ /// Note that setBounds() is not defined in the base class; it is
+ /// only defined in the derived classes. This is because each model uses
+ /// a different coordinate system.
+
+
+ /// Count of rows completed
+ int callback;
+
+ /// Height of the destination noise map, in points.
+ int destHeight;
+
+ /// Width of the destination noise map, in points.
+ int destWidth;
+
+ /// Destination noise map that will contain the coherent-noise values.
+ NoiseMap destNoiseMap;
+
+ /// Source noise module that will generate the coherent-noise values.
+ ModuleBase sourceModule;
+
+
+ public NoiseMapBuilder () throws ExceptionInvalidParam
+ {
+ callback = 0;
+ destHeight = 0;
+ destWidth = 0;
+ destNoiseMap = new NoiseMap(1,1);
+ sourceModule = new ModuleBase(0);
+ }
+
+ public NoiseMapBuilder (int height, int width) throws ExceptionInvalidParam
+ {
+ callback = 0;
+ destHeight = 0;
+ destWidth = 0;
+ destNoiseMap = new NoiseMap(height,width);
+ sourceModule = new ModuleBase(0);
+ }
+
+ /// Builds the noise map.
+ ///
+ /// @pre setBounds() was previously called.
+ /// @pre setDestNoiseMap() was previously called.
+ /// @pre setSourceModule() was previously called.
+ /// @pre The width and height values specified by setDestSize() are
+ /// positive.
+ /// @pre The width and height values specified by setDestSize() do not
+ /// exceed the maximum possible width and height for the noise map.
+ ///
+ /// @post The original contents of the destination noise map is
+ /// destroyed.
+ ///
+ /// @throw ExceptionInvalidParam See the preconditions.
+ /// @throw ExceptionOutOfMemory Out of memory.
+ ///
+ /// If this method is successful, the destination noise map contains
+ /// the coherent-noise values from the noise module specified by
+ /// setSourceModule().
+ public void build () throws ExceptionInvalidParam
+ {
+ //override in child classes
+ }
+
+ /// Returns the height of the destination noise map.
+ ///
+ /// @returns The height of the destination noise map, in points.
+ ///
+ /// This object does not change the height in the destination noise
+ /// map object until the build() method is called.
+ public double getDestHeight ()
+ {
+ return destHeight;
+ }
+
+ /// Returns the width of the destination noise map.
+ ///
+ /// @returns The width of the destination noise map, in points.
+ ///
+ /// This object does not change the height in the destination noise
+ /// map object until the build() method is called.
+ public double getDestWidth ()
+ {
+ return destWidth;
+ }
+
+ /// Sets the destination noise map.
+ ///
+ /// @param destNoiseMap The destination noise map.
+ ///
+ /// The destination noise map will contain the coherent-noise values
+ /// from this noise map after a successful call to the build() method.
+ ///
+ /// The destination noise map must exist throughout the lifetime of
+ /// this object unless another noise map replaces that noise map.
+ public void setDestNoiseMap (NoiseMap destNoiseMap)
+ {
+ this.destNoiseMap = destNoiseMap;
+ }
+
+ /// Sets the source module.
+ ///
+ /// @param sourceModule The source module.
+ ///
+ /// This object fills in a noise map with the coherent-noise values
+ /// from this source module.
+ ///
+ /// The source module must exist throughout the lifetime of this
+ /// object unless another noise module replaces that noise module.
+ public void setSourceModule (ModuleBase sourceModule)
+ {
+ this.sourceModule = sourceModule;
+ }
+
+ /// Sets the size of the destination noise map.
+ ///
+ /// @param destWidth The width of the destination noise map, in
+ /// points.
+ /// @param destHeight The height of the destination noise map, in
+ /// points.
+ ///
+ /// This method does not change the size of the destination noise map
+ /// until the build() method is called.
+ public void setDestSize (int destWidth, int destHeight)
+ {
+ this.destWidth = destWidth ;
+ this.destHeight = destHeight;
+ }
+
+ public NoiseMap getDestNoiseMap()
+ {
+ return destNoiseMap;
+ }
+
+ void setCallback (int callback)
+ {
+ this.callback = callback;
+ }
+
+}
\ No newline at end of file diff --git a/src/libnoiseforjava/util/NoiseMapBuilderCylinder.java b/src/libnoiseforjava/util/NoiseMapBuilderCylinder.java new file mode 100644 index 0000000..4d33219 --- /dev/null +++ b/src/libnoiseforjava/util/NoiseMapBuilderCylinder.java @@ -0,0 +1,213 @@ +/*
+ * Copyright (C) 2003, 2004 Jason Bevins (original libnoise code)
+ * Copyright 2010 Thomas J. Hodge (java port of libnoise)
+ *
+ * This file is part of libnoiseforjava.
+ *
+ * libnoiseforjava is a Java port of the C++ library libnoise, which may be found at
+ * http://libnoise.sourceforge.net/. libnoise was developed by Jason Bevins, who may be
+ * contacted at [email protected] (for great email, take off every 'zig').
+ * Porting to Java was done by Thomas Hodge, who may be contacted at
+ * [email protected] (remove every 'zag').
+ *
+ * libnoiseforjava is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * libnoiseforjava is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * libnoiseforjava. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package libnoiseforjava.util;
+
+import libnoiseforjava.exception.ExceptionInvalidParam;
+import libnoiseforjava.model.Cylinder;
+
+public class NoiseMapBuilderCylinder extends NoiseMapBuilder
+{
+
+ /// Builds a cylindrical noise map.
+ ///
+ /// This class builds a noise map by filling it with coherent-noise values
+ /// generated from the surface of a cylinder.
+ ///
+ /// This class describes these input values using an (angle, height)
+ /// coordinate system. After generating the coherent-noise value from the
+ /// input value, it then "flattens" these coordinates onto a plane so that
+ /// it can write the values into a two-dimensional noise map.
+ ///
+ /// The cylinder model has a radius of 1.0 unit and has infinite height.
+ /// The cylinder is oriented along the @a y axis. Its center is at the
+ /// origin.
+ ///
+ /// The x coordinate in the noise map represents the angle around the
+ /// cylinder's y axis. The y coordinate in the noise map represents the
+ /// height above the x-z plane.
+ ///
+ /// The application must provide the lower and upper angle bounds of the
+ /// noise map, in degrees, and the lower and upper height bounds of the
+ /// noise map, in units.
+
+ /// Lower angle boundary of the cylindrical noise map, in degrees.
+ double lowerAngleBound;
+
+ /// Lower height boundary of the cylindrical noise map, in units.
+ double lowerHeightBound;
+
+ /// Upper angle boundary of the cylindrical noise map, in degrees.
+ double upperAngleBound;
+
+ /// Upper height boundary of the cylindrical noise map, in units.
+ double upperHeightBound;
+
+
+
+ public NoiseMapBuilderCylinder () throws ExceptionInvalidParam
+ {
+ super();
+ lowerAngleBound = 0.0;
+ lowerHeightBound = 0.0;
+ upperAngleBound = 0.0;
+ upperHeightBound = 0.0;
+ }
+
+ public void build () throws ExceptionInvalidParam
+ {
+ if (upperAngleBound <= lowerAngleBound
+ || upperHeightBound <= lowerHeightBound
+ || destWidth <= 0
+ || destHeight <= 0
+ || sourceModule == null
+ || destNoiseMap == null)
+ throw new ExceptionInvalidParam ("Invalid Parameter in NoiseMapBuilderCylinder");
+
+
+ // Resize the destination noise map so that it can store the new output
+ // values from the source model.
+ destNoiseMap.setSize (destWidth, destHeight);
+
+ // Create the cylinder model.
+ Cylinder cylinderModel = new Cylinder();
+ cylinderModel.setModule (sourceModule);
+
+ double angleExtent = upperAngleBound - lowerAngleBound ;
+ double heightExtent = upperHeightBound - lowerHeightBound;
+ double xDelta = angleExtent / (double)destWidth ;
+ double yDelta = heightExtent / (double)destHeight;
+ double curAngle = lowerAngleBound ;
+ double curHeight = lowerHeightBound;
+
+ // Fill every point in the noise map with the output values from the model.
+ for (int y = 0; y < destHeight; y++)
+ {
+ curAngle = lowerAngleBound;
+ for (int x = 0; x < destWidth; x++)
+ {
+ float curValue = (float)cylinderModel.getValue (curAngle, curHeight);
+ destNoiseMap.setValue(x, y, curValue);
+ curAngle += xDelta;
+ }
+ curHeight += yDelta;
+ setCallback (y);
+ }
+ }
+
+ /// Returns the lower angle boundary of the cylindrical noise map.
+ ///
+ /// @returns The lower angle boundary of the noise map, in degrees.
+ public double getLowerAngleBound ()
+ {
+ return lowerAngleBound;
+ }
+
+ /// Returns the lower height boundary of the cylindrical noise map.
+ ///
+ /// @returns The lower height boundary of the noise map, in units.
+ ///
+ /// One unit is equal to the radius of the cylinder.
+ public double getLowerHeightBound ()
+ {
+ return lowerHeightBound;
+ }
+
+ /// Returns the upper angle boundary of the cylindrical noise map.
+ ///
+ /// @returns The upper angle boundary of the noise map, in degrees.
+ public double GetUpperAngleBound ()
+ {
+ return upperAngleBound;
+ }
+
+ /// Returns the upper height boundary of the cylindrical noise map.
+ ///
+ /// @returns The upper height boundary of the noise map, in units.
+ ///
+ /// One unit is equal to the radius of the cylinder.
+ public double getUpperHeightBound ()
+ {
+ return upperHeightBound;
+ }
+
+ /// Sets the coordinate boundaries of the noise map.
+ ///
+ /// @param lowerAngleBound The lower angle boundary of the noise map,
+ /// in degrees.
+ /// @param upperAngleBound The upper angle boundary of the noise map,
+ /// in degrees.
+ /// @param lowerHeightBound The lower height boundary of the noise
+ /// map, in units.
+ /// @param upperHeightBound The upper height boundary of the noise
+ /// map, in units.
+ ///
+ /// @pre The lower angle boundary is less than the upper angle
+ /// boundary.
+ /// @pre The lower height boundary is less than the upper height
+ /// boundary.
+ ///
+ /// @throw noise::ExceptionInvalidParam See the preconditions.
+ ///
+ /// One unit is equal to the radius of the cylinder.
+ public void setBounds (double lowerAngleBound, double upperAngleBound,
+ double lowerHeightBound, double upperHeightBound) throws ExceptionInvalidParam
+ {
+ if (lowerAngleBound >= upperAngleBound
+ || lowerHeightBound >= upperHeightBound)
+ throw new ExceptionInvalidParam ("Invalid Parameter in NoiseMapBuilder Cylinder");
+
+ this.lowerAngleBound = lowerAngleBound ;
+ this.upperAngleBound = upperAngleBound ;
+ this.lowerHeightBound = lowerHeightBound;
+ this.upperHeightBound = upperHeightBound;
+ }
+
+ public double getUpperAngleBound()
+ {
+ return upperAngleBound;
+ }
+
+ public void setLowerAngleBound(double lowerAngleBound)
+ {
+ this.lowerAngleBound = lowerAngleBound;
+ }
+
+ public void setLowerHeightBound(double lowerHeightBound)
+ {
+ this.lowerHeightBound = lowerHeightBound;
+ }
+
+ public void setUpperAngleBound(double upperAngleBound)
+ {
+ this.upperAngleBound = upperAngleBound;
+ }
+
+ public void setUpperHeightBound(double upperHeightBound)
+ {
+ this.upperHeightBound = upperHeightBound;
+ }
+
+}
diff --git a/src/libnoiseforjava/util/NoiseMapBuilderPlane.java b/src/libnoiseforjava/util/NoiseMapBuilderPlane.java new file mode 100644 index 0000000..20e5fcb --- /dev/null +++ b/src/libnoiseforjava/util/NoiseMapBuilderPlane.java @@ -0,0 +1,245 @@ +/*
+ * Copyright (C) 2003, 2004 Jason Bevins (original libnoise code)
+ * Copyright 2010 Thomas J. Hodge (java port of libnoise)
+ *
+ * This file is part of libnoiseforjava.
+ *
+ * libnoiseforjava is a Java port of the C++ library libnoise, which may be found at
+ * http://libnoise.sourceforge.net/. libnoise was developed by Jason Bevins, who may be
+ * contacted at [email protected] (for great email, take off every 'zig').
+ * Porting to Java was done by Thomas Hodge, who may be contacted at
+ * [email protected] (remove every 'zag').
+ *
+ * libnoiseforjava is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * libnoiseforjava is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * libnoiseforjava. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package libnoiseforjava.util;
+
+import libnoiseforjava.Interp;
+import libnoiseforjava.exception.ExceptionInvalidParam;
+import libnoiseforjava.model.Plane;
+
+public class NoiseMapBuilderPlane extends NoiseMapBuilder
+{
+ /// Builds a planar noise map.
+ ///
+ /// This class builds a noise map by filling it with coherent-noise values
+ /// generated from the surface of a plane.
+ ///
+ /// This class describes these input values using (x, z) coordinates.
+ /// Their y coordinates are always 0.0.
+ ///
+ /// The application must provide the lower and upper x coordinate bounds
+ /// of the noise map, in units, and the lower and upper z coordinate
+ /// bounds of the noise map, in units.
+ ///
+ /// To make a tileable noise map with no seams at the edges, call the
+ /// enableSeamless() method.
+
+ /// A flag specifying whether seamless tiling is enabled.
+ boolean isSeamlessEnabled;
+
+ /// Lower x boundary of the planar noise map, in units.
+ double lowerXBound;
+
+ /// Lower z boundary of the planar noise map, in units.
+ double lowerZBound;
+
+ /// Upper x boundary of the planar noise map, in units.
+ double upperXBound;
+
+ /// Upper z boundary of the planar noise map, in units.
+ double upperZBound;
+
+
+ public NoiseMapBuilderPlane () throws ExceptionInvalidParam
+ {
+ super();
+ isSeamlessEnabled = false;
+ lowerXBound = 0.0;
+ lowerZBound = 0.0;
+ upperXBound = 0.0;
+ upperZBound = 0.0;
+ }
+
+ public NoiseMapBuilderPlane (int height, int width) throws ExceptionInvalidParam
+ {
+ super(height, width);
+ isSeamlessEnabled = false;
+ lowerXBound = 0.0;
+ lowerZBound = 0.0;
+ upperXBound = 0.0;
+ upperZBound = 0.0;
+ }
+
+ public void build () throws ExceptionInvalidParam
+ {
+ if ( upperXBound <= lowerXBound
+ || upperZBound <= lowerZBound
+ || destWidth <= 0
+ || destHeight <= 0
+ || sourceModule == null
+ || destNoiseMap == null)
+ throw new ExceptionInvalidParam ("Invalid parameter in NoiseMapBuilderPlane");
+
+ // Resize the destination noise map so that it can store the new output
+ // values from the source model.
+ destNoiseMap.setSize (destWidth, destHeight);
+
+ // Create the plane model.
+ Plane planeModel = new Plane();
+ planeModel.setModule (sourceModule);
+
+ double xExtent = upperXBound - lowerXBound;
+ double zExtent = upperZBound - lowerZBound;
+ double xDelta = xExtent / (double)destWidth ;
+ double zDelta = zExtent / (double)destHeight;
+ double xCur = lowerXBound;
+ double zCur = lowerZBound;
+
+ // Fill every point in the noise map with the output values from the model.
+ for (int z = 0; z < destHeight; z++)
+ {
+ xCur = lowerXBound;
+ for (int x = 0; x < destWidth; x++)
+ {
+ double finalValue;
+
+ if (!isSeamlessEnabled)
+ finalValue = planeModel.getValue (xCur, zCur);
+ else
+ {
+ double swValue, seValue, nwValue, neValue;
+ swValue = planeModel.getValue (xCur, zCur);
+ seValue = planeModel.getValue (xCur + xExtent, zCur);
+ nwValue = planeModel.getValue (xCur, zCur + zExtent);
+ neValue = planeModel.getValue (xCur + xExtent, zCur + zExtent);
+ double xBlend = 1.0 - ((xCur - lowerXBound) / xExtent);
+ double zBlend = 1.0 - ((zCur - lowerZBound) / zExtent);
+ double z0 = Interp.linearInterp (swValue, seValue, xBlend);
+ double z1 = Interp.linearInterp (nwValue, neValue, xBlend);
+ finalValue = Interp.linearInterp (z0, z1, zBlend);
+ }
+
+ destNoiseMap.setValue(x, z, finalValue);
+ xCur += xDelta;
+ }
+ zCur += zDelta;
+ setCallback (z);
+ }
+ }
+
+ /// Enables or disables seamless tiling.
+ ///
+ /// @param enable A flag that enables or disables seamless tiling.
+ ///
+ /// Enabling seamless tiling builds a noise map with no seams at the
+ /// edges. This allows the noise map to be tileable.
+ public void enableSeamless (boolean enable)
+ {
+ isSeamlessEnabled = enable;
+ }
+
+ /// Returns the lower x boundary of the planar noise map.
+ ///
+ /// @returns The lower x boundary of the planar noise map, in units.
+ public double getLowerXBound ()
+ {
+ return lowerXBound;
+ }
+
+ /// Returns the lower z boundary of the planar noise map.
+ ///
+ /// @returns The lower z boundary of the noise map, in units.
+ public double getLowerZBound ()
+ {
+ return lowerZBound;
+ }
+
+ /// Returns the upper x boundary of the planar noise map.
+ ///
+ /// @returns The upper x boundary of the noise map, in units.
+ public double getUpperXBound ()
+ {
+ return upperXBound;
+ }
+
+ /// Returns the upper z boundary of the planar noise map.
+ ///
+ /// @returns The upper z boundary of the noise map, in units.
+ public double getUpperZBound ()
+ {
+ return upperZBound;
+ }
+
+ /// Determines if seamless tiling is enabled.
+ ///
+ /// @returns
+ /// - @a true if seamless tiling is enabled.
+ /// - @a false if seamless tiling is disabled.
+ ///
+ /// Enabling seamless tiling builds a noise map with no seams at the
+ /// edges. This allows the noise map to be tileable.
+ public boolean isSeamlessEnabled ()
+ {
+ return isSeamlessEnabled;
+ }
+
+ /// Sets the boundaries of the planar noise map.
+ ///
+ /// @param lowerXBound The lower x boundary of the noise map, in
+ /// units.
+ /// @param upperXBound The upper x boundary of the noise map, in
+ /// units.
+ /// @param lowerZBound The lower z boundary of the noise map, in
+ /// units.
+ /// @param upperZBound The upper z boundary of the noise map, in
+ /// units.
+ ///
+ /// @pre The lower x boundary is less than the upper x boundary.
+ /// @pre The lower z boundary is less than the upper z boundary.
+ ///
+ /// @throw ExceptionInvalidParam See the preconditions.
+ public void setBounds (double lowerXBound, double upperXBound,
+ double lowerZBound, double upperZBound) throws ExceptionInvalidParam
+ {
+ if (lowerXBound >= upperXBound || lowerZBound >= upperZBound)
+ throw new ExceptionInvalidParam ("Invalid parameter in NoiseMapBuilderPlane");
+
+ this.lowerXBound = lowerXBound;
+ this.upperXBound = upperXBound;
+ this.lowerZBound = lowerZBound;
+ this.upperZBound = upperZBound;
+ }
+
+ public void setLowerXBound(double lowerXBound)
+ {
+ this.lowerXBound = lowerXBound;
+ }
+
+ public void setLowerZBound(double lowerZBound)
+ {
+ this.lowerZBound = lowerZBound;
+ }
+
+ public void setUpperXBound(double upperXBound)
+ {
+ this.upperXBound = upperXBound;
+ }
+
+ public void setUpperZBound(double upperZBound)
+ {
+ this.upperZBound = upperZBound;
+ }
+
+}
diff --git a/src/libnoiseforjava/util/NoiseMapBuilderSphere.java b/src/libnoiseforjava/util/NoiseMapBuilderSphere.java new file mode 100644 index 0000000..0aa560a --- /dev/null +++ b/src/libnoiseforjava/util/NoiseMapBuilderSphere.java @@ -0,0 +1,195 @@ +/*
+ * Copyright (C) 2003, 2004 Jason Bevins (original libnoise code)
+ * Copyright 2010 Thomas J. Hodge (java port of libnoise)
+ *
+ * This file is part of libnoiseforjava.
+ *
+ * libnoiseforjava is a Java port of the C++ library libnoise, which may be found at
+ * http://libnoise.sourceforge.net/. libnoise was developed by Jason Bevins, who may be
+ * contacted at [email protected] (for great email, take off every 'zig').
+ * Porting to Java was done by Thomas Hodge, who may be contacted at
+ * [email protected] (remove every 'zag').
+ *
+ * libnoiseforjava is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * libnoiseforjava is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * libnoiseforjava. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package libnoiseforjava.util;
+
+import libnoiseforjava.exception.ExceptionInvalidParam;
+import libnoiseforjava.model.Sphere;
+
+public class NoiseMapBuilderSphere extends NoiseMapBuilder
+{
+ /// Builds a spherical noise map.
+ ///
+ /// This class builds a noise map by filling it with coherent-noise values
+ /// generated from the surface of a sphere.
+ ///
+ /// This class describes these input values using a (latitude, longitude)
+ /// coordinate system. After generating the coherent-noise value from the
+ /// input value, it then "flattens" these coordinates onto a plane so that
+ /// it can write the values into a two-dimensional noise map.
+ ///
+ /// The sphere model has a radius of 1.0 unit. Its center is at the
+ /// origin.
+ ///
+ /// The x coordinate in the noise map represents the longitude. The y
+ /// coordinate in the noise map represents the latitude.
+ ///
+ /// The application must provide the southern, northern, western, and
+ /// eastern bounds of the noise map, in degrees.
+
+ /// Eastern boundary of the spherical noise map, in degrees.
+ double eastLonBound;
+
+ /// Northern boundary of the spherical noise map, in degrees.
+ double northLatBound;
+
+ /// Southern boundary of the spherical noise map, in degrees.
+ double southLatBound;
+
+ /// Western boundary of the spherical noise map, in degrees.
+ double westLonBound;
+
+ public NoiseMapBuilderSphere () throws ExceptionInvalidParam
+ {
+ super();
+ eastLonBound = 0.0;
+ northLatBound = 0.0;
+ southLatBound = 0.0;
+ westLonBound = 0.0;
+ }
+
+ public void build () throws ExceptionInvalidParam
+ {
+ if ( eastLonBound <= westLonBound
+ || northLatBound <= southLatBound
+ || destWidth <= 0
+ || destHeight <= 0
+ || sourceModule == null
+ || destNoiseMap == null)
+ throw new ExceptionInvalidParam ("Invalid Parameter in NoiseMapBuilderSphere");
+
+
+ // Resize the destination noise map so that it can store the new output
+ // values from the source model.
+ destNoiseMap.setSize (destWidth, destHeight);
+
+ // Create the plane model.
+ Sphere sphereModel = new Sphere();
+ sphereModel.setModule (sourceModule);
+
+ double lonExtent = eastLonBound - westLonBound ;
+ double latExtent = northLatBound - southLatBound;
+ double xDelta = lonExtent / (double)destWidth ;
+ double yDelta = latExtent / (double)destHeight;
+ double curLon = westLonBound ;
+ double curLat = southLatBound;
+
+ // Fill every point in the noise map with the output values from the model.
+ for (int y = 0; y < destHeight; y++)
+ {
+ curLon = westLonBound;
+ for (int x = 0; x < destWidth; x++)
+ {
+ float curValue = (float)sphereModel.getValue (curLat, curLon);
+ destNoiseMap.setValue(x, y, curValue);
+ curLon += xDelta;
+ }
+ curLat += yDelta;
+ setCallback(y);
+
+ }
+ }
+
+ /// Returns the eastern boundary of the spherical noise map.
+ ///
+ /// @returns The eastern boundary of the noise map, in degrees.
+ public double getEastLonBound ()
+ {
+ return eastLonBound;
+ }
+
+ /// Returns the northern boundary of the spherical noise map
+ ///
+ /// @returns The northern boundary of the noise map, in degrees.
+ public double getNorthLatBound ()
+ {
+ return northLatBound;
+ }
+
+ /// Returns the southern boundary of the spherical noise map
+ ///
+ /// @returns The southern boundary of the noise map, in degrees.
+ public double getSouthLatBound ()
+ {
+ return southLatBound;
+ }
+
+ /// Returns the western boundary of the spherical noise map
+ ///
+ /// @returns The western boundary of the noise map, in degrees.
+ public double getWestLonBound ()
+ {
+ return westLonBound;
+ }
+
+ /// Sets the coordinate boundaries of the noise map.
+ ///
+ /// @param southLatBound The southern boundary of the noise map, in
+ /// degrees.
+ /// @param northLatBound The northern boundary of the noise map, in
+ /// degrees.
+ /// @param westLonBound The western boundary of the noise map, in
+ /// degrees.
+ /// @param eastLonBound The eastern boundary of the noise map, in
+ /// degrees.
+ ///
+ /// @pre The southern boundary is less than the northern boundary.
+ /// @pre The western boundary is less than the eastern boundary.
+ ///
+ /// @throw noise::ExceptionInvalidParam See the preconditions.
+ public void setBounds (double southLatBound, double northLatBound,
+ double westLonBound, double eastLonBound) throws ExceptionInvalidParam
+ {
+ if (southLatBound >= northLatBound
+ || westLonBound >= eastLonBound)
+ throw new ExceptionInvalidParam ("Invalid Parameter in NoiseMapBuilderSphere");
+
+ this.southLatBound = southLatBound;
+ this.northLatBound = northLatBound;
+ this.westLonBound = westLonBound ;
+ this.eastLonBound = eastLonBound ;
+ }
+
+ public void setEastLonBound(double eastLonBound)
+ {
+ this.eastLonBound = eastLonBound;
+ }
+
+ public void setNorthLatBound(double northLatBound)
+ {
+ this.northLatBound = northLatBound;
+ }
+
+ public void setSouthLatBound(double southLatBound)
+ {
+ this.southLatBound = southLatBound;
+ }
+
+ public void setWestLonBound(double westLonBound)
+ {
+ this.westLonBound = westLonBound;
+ }
+
+}
diff --git a/src/libnoiseforjava/util/RendererImage.java b/src/libnoiseforjava/util/RendererImage.java new file mode 100644 index 0000000..e437f89 --- /dev/null +++ b/src/libnoiseforjava/util/RendererImage.java @@ -0,0 +1,755 @@ +/*
+ * Copyright (C) 2003, 2004 Jason Bevins (original libnoise code)
+ * Copyright 2010 Thomas J. Hodge (java port of libnoise)
+ *
+ * This file is part of libnoiseforjava.
+ *
+ * libnoiseforjava is a Java port of the C++ library libnoise, which may be found at
+ * http://libnoise.sourceforge.net/. libnoise was developed by Jason Bevins, who may be
+ * contacted at [email protected] (for great email, take off every 'zig').
+ * Porting to Java was done by Thomas Hodge, who may be contacted at
+ * [email protected] (remove every 'zag').
+ *
+ * libnoiseforjava is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * libnoiseforjava is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * libnoiseforjava. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package libnoiseforjava.util;
+
+import libnoiseforjava.Interp;
+import libnoiseforjava.exception.ExceptionInvalidParam;
+
+public class RendererImage {
+
+ // / Renders an image from a noise map.
+ // /
+ // / This class renders an image given the contents of a noise-map object.
+ // /
+ // / An application can configure the output of the image in three ways:
+ // / - Specify the color gradient.
+ // / - Specify the light source parameters.
+ // / - Specify the background image.
+ // /
+ // / <b>Specify the color gradient</b>
+ // /
+ // / This class uses a color gradient to calculate the color for each pixel
+ // / in the destination image according to the value from the corresponding
+ // / position in the noise map.
+ // /
+ // / A color gradient is a list of gradually-changing colors. A color
+ // / gradient is defined by a list of <i>gradient points</i>. Each
+ // / gradient point has a position and a color. In a color gradient, the
+ // / colors between two adjacent gradient points are linearly interpolated.
+ // /
+ // / For example, suppose this class contains the following color gradient:
+ // /
+ // / - -1.0 maps to dark blue.
+ // / - -0.2 maps to light blue.
+ // / - -0.1 maps to tan.
+ // / - 0.0 maps to green.
+ // / - 1.0 maps to white.
+ // /
+ // / The value 0.5 maps to a greenish-white color because 0.5 is halfway
+ // / between 0.0 (mapped to green) and 1.0 (mapped to white).
+ // /
+ // / The value -0.6 maps to a medium blue color because -0.6 is halfway
+ // / between -1.0 (mapped to dark blue) and -0.2 (mapped to light blue).
+ // /
+ // / The color gradient requires a minimum of two gradient points.
+ // /
+ // / This class contains two pre-made gradients: a grayscale gradient and a
+ // / color gradient suitable for terrain. To use these pre-made gradients,
+ // / call the buildGrayscaleGradient() or buildTerrainGradient() methods,
+ // / respectively.
+ // /
+ // / @note The color value passed to addGradientPoint() has an alpha
+ // / channel. This alpha channel specifies how a pixel in the background
+ // / image (if specified) is blended with the calculated color. If the
+ // / alpha value is high, this class weighs the blend towards the
+ // / calculated color, and if the alpha value is low, this class weighs the
+ // / blend towards the color from the corresponding pixel in the background
+ // / image.
+ // /
+ // / <b>Specify the light source parameters</b>
+ // /
+ // / This class contains a parallel light source that lights the image. It
+ // / interprets the noise map as a bump map.
+ // /
+ // / To enable or disable lighting, pass a Boolean value to the
+ // / enableLight() method.
+ // /
+ // / To set the position of the light source in the "sky", call the
+ // / setLightAzimuth() and setLightElev() methods.
+ // /
+ // / To set the color of the light source, call the setLightColor() method.
+ // /
+ // / To set the intensity of the light source, call the setLightIntensity()
+ // / method. A good intensity value is 2.0, although that value tends to
+ // / "wash out" very light colors from the image.
+ // /
+ // / To set the contrast amount between areas in light and areas in shadow,
+ // / call the setLightContrast() method. Determining the correct contrast
+ // / amount requires some trial and error, but if your application
+ // / interprets the noise map as a height map that has its elevation values
+ // / measured in meters and has a horizontal resolution of @a h meters, a
+ // / good contrast amount to use is ( 1.0 / @a h ).
+ // /
+ // / <b>Specify the background image</b>
+ // /
+ // / To specify a background image, pass an Image object to the
+ // / setBackgroundImage() method.
+ // /
+ // / This class determines the color of a pixel in the destination image by
+ // / blending the calculated color with the color of the corresponding
+ // / pixel from the background image.
+ // /
+ // / The blend amount is determined by the alpha of the calculated color.
+ // / If the alpha value is high, this class weighs the blend towards the
+ // / calculated color, and if the alpha value is low, this class weighs the
+ // / blend towards the color from the corresponding pixel in the background
+ // / image.
+ // /
+ // / <b>Rendering the image</b>
+ // /
+ // / To render the image, perform the following steps:
+ // / - Pass a NoiseMap object to the setSourceNoiseMap() method.
+ // / - Pass an ImageCafe object to the setDestImage() method.
+ // / - Pass an ImageCafe object to the setBackgroundImage() method
+ // (optional)
+ // / - Call the render() method.
+
+ static final double SQRT_2 = 1.4142135623730950488;
+
+ // / The cosine of the azimuth of the light source.
+ double cosAzimuth;
+
+ // / The cosine of the elevation of the light source.
+ double cosElev;
+
+ // / The color gradient used to specify the image colors.
+ GradientColor gradient;
+
+ // / A flag specifying whether lighting is enabled.
+ boolean isLightEnabled;
+
+ // / A flag specifying whether wrapping is enabled.
+ boolean isWrapEnabled;
+
+ // / The azimuth of the light source, in degrees.
+ double lightAzimuth;
+
+ // / The brightness of the light source.
+ double lightBrightness;
+
+ // / The color of the light source.
+ ColorCafe lightColor;
+
+ // / The contrast between areas in light and areas in shadow.
+ double lightContrast;
+
+ // / The elevation of the light source, in degrees.
+ double lightElev;
+
+ // / The intensity of the light source.
+ double lightIntensity;
+
+ // / A pointer to the background image.
+ ImageCafe backgroundImage;
+
+ // / A pointer to the destination image.
+ ImageCafe destImageCafe;
+
+ // / A pointer to the source noise map.
+ NoiseMap sourceNoiseMap;
+
+ // / Used by the calcLightIntensity() method to recalculate the light
+ // / values only if the light parameters change.
+ // /
+ // / When the light parameters change, this value is set to True. When
+ // / the calcLightIntensity() method is called, this value is set to
+ // / false.
+ boolean recalcLightValues;
+
+ // / The sine of the azimuth of the light source.
+ double sinAzimuth;
+
+ // / The sine of the elevation of the light source.
+ double sinElev;
+
+ public RendererImage() throws ExceptionInvalidParam {
+ isLightEnabled = false;
+ isWrapEnabled = false;
+ lightAzimuth = 45.0;
+ lightBrightness = 1.0;
+ lightColor = new ColorCafe(255, 255, 255, 255);
+ lightContrast = 1.0;
+ lightElev = 45.0;
+ lightIntensity = 1.0;
+ backgroundImage = null;
+ destImageCafe = null;
+ sourceNoiseMap = null;
+ recalcLightValues = true;
+
+ buildGrayscaleGradient();
+ }
+
+ // / Adds a gradient point to this gradient object.
+ // /
+ // / @param gradientPos The position of this gradient point.
+ // / @param gradientColor The color of this gradient point.
+ // /
+ // / @pre No two gradient points have the same position.
+ // /
+ // / @throw noise::ExceptionInvalidParam See the preconditions.
+ // /
+ // / This object uses a color gradient to calculate the color for each
+ // / pixel in the destination image according to the value from the
+ // / corresponding position in the noise map.
+ // /
+ // / The gradient requires a minimum of two gradient points.
+ // /
+ // / The specified color value passed to this method has an alpha
+ // / channel. This alpha channel specifies how a pixel in the
+ // / background image (if specified) is blended with the calculated
+ // / color. If the alpha value is high, this object weighs the blend
+ // / towards the calculated color, and if the alpha value is low, this
+ // / object weighs the blend towards the color from the corresponding
+ // / pixel in the background image.
+ public void addGradientPoint(double gradientPos, ColorCafe gradientColor) throws ExceptionInvalidParam {
+ gradient.addGradientPoint(gradientPos, gradientColor);
+ }
+
+ // / Builds a grayscale gradient.
+ // /
+ // / @post The original gradient is cleared and a grayscale gradient is
+ // / created.
+ // /
+ // / This color gradient contains the following gradient points:
+ // / - -1.0 maps to black
+ // / - 1.0 maps to white
+ public void buildGrayscaleGradient() throws ExceptionInvalidParam {
+ clearGradient();
+ gradient.addGradientPoint(-1.0, new ColorCafe(0, 0, 0, 255));
+ gradient.addGradientPoint(1.0, new ColorCafe(255, 255, 255, 255));
+ }
+
+ // / Builds a color gradient suitable for terrain.
+ // /
+ // / @post The original gradient is cleared and a terrain gradient is
+ // / created.
+ // /
+ // / This gradient color at position 0.0 is the "sea level". Above
+ // / that value, the gradient contains greens, browns, and whites.
+ // / Below that value, the gradient contains various shades of blue.
+ public void buildTerrainGradient() throws ExceptionInvalidParam {
+ clearGradient();
+ gradient.addGradientPoint(-1.00, new ColorCafe(0, 0, 128, 255));
+ gradient.addGradientPoint(-0.20, new ColorCafe(32, 64, 128, 255));
+ gradient.addGradientPoint(-0.04, new ColorCafe(64, 96, 192, 255));
+ gradient.addGradientPoint(-0.02, new ColorCafe(192, 192, 128, 255));
+ gradient.addGradientPoint(0.00, new ColorCafe(0, 192, 0, 255));
+ gradient.addGradientPoint(0.25, new ColorCafe(192, 192, 0, 255));
+ gradient.addGradientPoint(0.50, new ColorCafe(160, 96, 64, 255));
+ gradient.addGradientPoint(0.75, new ColorCafe(128, 255, 255, 255));
+ gradient.addGradientPoint(1.00, new ColorCafe(255, 255, 255, 255));
+ }
+
+ // / Calculates the destination color.
+ // /
+ // / @param sourceColor The source color generated from the color
+ // / gradient.
+ // / @param backgroundColor The color from the background image at the
+ // / corresponding position.
+ // / @param lightValue The intensity of the light at that position.
+ // /
+ // / @returns The destination color.
+ public ColorCafe calcDestColor(ColorCafe sourceColor, ColorCafe backgroundColor, double lightValue) {
+ double sourceRed = (double) sourceColor.red / 255.0;
+ double sourceGreen = (double) sourceColor.green / 255.0;
+ double sourceBlue = (double) sourceColor.blue / 255.0;
+ double sourceAlpha = (double) sourceColor.alpha / 255.0;
+ double backgroundRed = (double) backgroundColor.red / 255.0;
+ double backgroundGreen = (double) backgroundColor.green / 255.0;
+ double backgroundBlue = (double) backgroundColor.blue / 255.0;
+
+ // First, blend the source color to the background color using the alpha
+ // of the source color.
+ double red = Interp.linearInterp(backgroundRed, sourceRed, sourceAlpha);
+ double green = Interp.linearInterp(backgroundGreen, sourceGreen, sourceAlpha);
+ double blue = Interp.linearInterp(backgroundBlue, sourceBlue, sourceAlpha);
+
+ if (isLightEnabled) {
+ // Now calculate the light color.
+ double lightRed = lightValue * (double) lightColor.red / 255.0;
+ double lightGreen = lightValue * (double) lightColor.green / 255.0;
+ double lightBlue = lightValue * (double) lightColor.blue / 255.0;
+
+ // Apply the light color to the new color.
+ red *= lightRed;
+ green *= lightGreen;
+ blue *= lightBlue;
+ }
+
+ // Clamp the color channels to the (0..1) range.
+ red = (red < 0.0) ? 0.0 : red;
+ red = (red > 1.0) ? 1.0 : red;
+ green = (green < 0.0) ? 0.0 : green;
+ green = (green > 1.0) ? 1.0 : green;
+ blue = (blue < 0.0) ? 0.0 : blue;
+ blue = (blue > 1.0) ? 1.0 : blue;
+
+ // Rescale the color channels to the noise::uint8 (0..255) range and
+ // return
+ // the new color.
+ ColorCafe newColor = new ColorCafe((int) (red * 255.0) & 0xff, (int) (green * 255.0) & 0xff,
+ (int) (blue * 255.0) & 0xff, Math.max(sourceColor.alpha, backgroundColor.alpha));
+ return newColor;
+ }
+
+ // / Calculates the intensity of the light given some elevation values.
+ // /
+ // / @param center Elevation of the center point.
+ // / @param left Elevation of the point directly left of the center
+ // / point.
+ // / @param right Elevation of the point directly right of the center
+ // / point.
+ // / @param down Elevation of the point directly below the center
+ // / point.
+ // / @param up Elevation of the point directly above the center point.
+ // /
+ // / These values come directly from the noise map.
+ public double calcLightIntensity(double center, double left, double right, double down, double up) {
+ // Recalculate the sine and cosine of the various light values if
+ // necessary so it does not have to be calculated each time this method
+ // is
+ // called.
+ if (recalcLightValues) {
+ cosAzimuth = Math.cos(Math.toRadians(lightAzimuth));
+ sinAzimuth = Math.sin(Math.toRadians(lightAzimuth));
+ cosElev = Math.cos(Math.toRadians(lightElev));
+ sinElev = Math.sin(Math.toRadians(lightElev));
+ recalcLightValues = false;
+ }
+
+ // Now do the lighting calculations.
+ double I_MAX = 1.0;
+ double io = I_MAX * SQRT_2 * sinElev / 2.0;
+ double ix = (I_MAX - io) * lightContrast * SQRT_2 * cosElev * cosAzimuth;
+ double iy = (I_MAX - io) * lightContrast * SQRT_2 * cosElev * sinAzimuth;
+ double intensity = (ix * (left - right) + iy * (down - up) + io);
+
+ if (intensity < 0.0)
+ intensity = 0.0;
+
+ return intensity;
+ }
+
+ // / Clears the color gradient.
+ // /
+ // / Before calling the render() method, the application must specify a
+ // / new color gradient with at least two gradient points.
+ public void clearGradient() {
+ gradient = new GradientColor();
+ gradient.clear();
+ }
+
+ // / Renders the destination image using the contents of the source
+ // / noise map and an optional background image.
+ // /
+ // / @pre setSourceNoiseMap() has been previously called.
+ // / @pre setDestImage() has been previously called.
+ // / @pre There are at least two gradient points in the color gradient.
+ // / @pre No two gradient points have the same position.
+ // / @pre If a background image was specified, it has the exact same
+ // / size as the source height map.
+ // /
+ // / @post The original contents of the destination image is destroyed.
+ // /
+ // / @throw ExceptionInvalidParam See the preconditions.
+ // /
+ // / The background image and the destination image can safely refer to
+ // / the same image, although in this case, the destination image is
+ // / irretrievably blended into the background image.
+ public void render() throws ExceptionInvalidParam {
+ if (sourceNoiseMap == null || destImageCafe == null || sourceNoiseMap.getWidth() <= 0
+ || sourceNoiseMap.getHeight() <= 0 || gradient.getGradientPointCount() < 2)
+ throw new ExceptionInvalidParam("Invalid Parameter in RendererImage");
+
+ int width = sourceNoiseMap.getWidth();
+ int height = sourceNoiseMap.getHeight();
+
+ // If a background image was provided, make sure it is the same size the
+ // source noise map.
+ if (backgroundImage != null)
+ if (backgroundImage.getWidth() != width || backgroundImage.getHeight() != height)
+ throw new ExceptionInvalidParam("Invalid Parameter in RendererImage");
+
+ // Create the destination image. It is safe to reuse it if this is also
+ // the
+ // background image.
+ if (destImageCafe != backgroundImage)
+ destImageCafe.setSize(width, height);
+
+ for (int y = 0; y < height; y++) {
+ @SuppressWarnings("unused")
+ ColorCafe background = new ColorCafe(255, 255, 255, 255);
+
+ for (int x = 0; x < width; x++) {
+ // Get the color based on the value at the current point in the
+ // noise
+ // map.
+ ColorCafe destColor = gradient.getColor(sourceNoiseMap.getValue(x, y));
+
+ // If lighting is enabled, calculate the light intensity based
+ // on the
+ // rate of change at the current point in the noise map.
+ double lightIntensity;
+ if (isLightEnabled) {
+ // Calculate the positions of the current point's
+ // four-neighbors.
+ int xLeftOffset, xRightOffset;
+ int yUpOffset, yDownOffset;
+ if (isWrapEnabled) {
+ if (x == 0) {
+ xLeftOffset = (int) width - 1;
+ xRightOffset = 1;
+ } else if (x == (int) width - 1) {
+ xLeftOffset = -1;
+ xRightOffset = -((int) width - 1);
+ } else {
+ xLeftOffset = -1;
+ xRightOffset = 1;
+ }
+
+ if (y == 0) {
+ yDownOffset = (int) height - 1;
+ yUpOffset = 1;
+ } else if (y == (int) height - 1) {
+ yDownOffset = -1;
+ yUpOffset = -((int) height - 1);
+ } else {
+ yDownOffset = -1;
+ yUpOffset = 1;
+ }
+ } else {
+ if (x == 0) {
+ xLeftOffset = 0;
+ xRightOffset = 1;
+ } else if (x == (int) width - 1) {
+ xLeftOffset = -1;
+ xRightOffset = 0;
+ } else {
+ xLeftOffset = -1;
+ xRightOffset = 1;
+ }
+
+ if (y == 0) {
+ yDownOffset = 0;
+ yUpOffset = 1;
+ } else if (y == (int) height - 1) {
+ yDownOffset = -1;
+ yUpOffset = 0;
+ } else {
+ yDownOffset = -1;
+ yUpOffset = 1;
+ }
+ }
+
+ // Get the noise value of the current point in the source
+ // noise map
+ // and the noise values of its four-neighbors.
+ double nc = (double) (sourceNoiseMap.getValue(x, y));
+ double nl = (double) (sourceNoiseMap.getValue(x + xLeftOffset, y));
+ double nr = (double) (sourceNoiseMap.getValue(x + xRightOffset, y));
+ double nd = (double) (sourceNoiseMap.getValue(x, y + yDownOffset));
+ double nu = (double) (sourceNoiseMap.getValue(x, y + yUpOffset));
+
+ // Now we can calculate the lighting intensity.
+ lightIntensity = calcLightIntensity(nc, nl, nr, nd, nu);
+ lightIntensity *= lightBrightness;
+
+ } else {
+ // These values will apply no lighting to the destination
+ // image.
+ lightIntensity = 1.0;
+ }
+
+ // Get the current background color from the background image.
+ ColorCafe backgroundColor = new ColorCafe(255, 255, 255, 255);
+ if (backgroundImage != null)
+ backgroundColor = backgroundImage.getValue(x, y);
+
+ // Blend the destination color, background color, and the light
+ // intensity together, then update the destination image with
+ // that
+ // color.
+ destImageCafe.setValue(x, y, calcDestColor(destColor, backgroundColor, lightIntensity));
+ }
+ }
+ }
+
+ // / Enables or disables the light source.
+ // /
+ // / @param enable A flag that enables or disables the light source.
+ // /
+ // / If the light source is enabled, this object will interpret the
+ // / noise map as a bump map.
+ public void enableLight(boolean enable) {
+ isLightEnabled = enable;
+ }
+
+ // / Enables or disables noise-map wrapping.
+ // /
+ // / @param enable A flag that enables or disables noise-map wrapping.
+ // /
+ // / This object requires five points (the initial point and its four
+ // / neighbors) to calculate light shading. If wrapping is enabled,
+ // / and the initial point is on the edge of the noise map, the
+ // / appropriate neighbors that lie outside of the noise map will
+ // / "wrap" to the opposite side(s) of the noise map. Otherwise, the
+ // / appropriate neighbors are cropped to the edge of the noise map.
+ // /
+ // / Enabling wrapping is useful when creating spherical renderings and
+ // / tileable textures.
+ public void enableWrap(boolean enable) {
+ isWrapEnabled = enable;
+ }
+
+ // / Returns the azimuth of the light source, in degrees.
+ // /
+ // / @returns The azimuth of the light source.
+ // /
+ // / The azimuth is the location of the light source around the
+ // / horizon:
+ // / - 0.0 degrees is east.
+ // / - 90.0 degrees is north.
+ // / - 180.0 degrees is west.
+ // / - 270.0 degrees is south.
+ public double getLightAzimuth() {
+ return lightAzimuth;
+ }
+
+ // / Returns the brightness of the light source.
+ // /
+ // / @returns The brightness of the light source.
+ public double getLightBrightness() {
+ return lightBrightness;
+ }
+
+ // / Returns the color of the light source.
+ // /
+ // / @returns The color of the light source.
+ public ColorCafe getLightColor() {
+ return lightColor;
+ }
+
+ // / Returns the contrast of the light source.
+ // /
+ // / @returns The contrast of the light source.
+ // /
+ // / The contrast specifies how sharp the boundary is between the
+ // / light-facing areas and the shadowed areas.
+ // /
+ // / The contrast determines the difference between areas in light and
+ // / areas in shadow. Determining the correct contrast amount requires
+ // / some trial and error, but if your application interprets the noise
+ // / map as a height map that has a spatial resolution of @a h meters
+ // / and an elevation resolution of 1 meter, a good contrast amount to
+ // / use is ( 1.0 / @a h ).
+ public double getLightContrast() {
+ return lightContrast;
+ }
+
+ // / Returns the elevation of the light source, in degrees.
+ // /
+ // / @returns The elevation of the light source.
+ // /
+ // / The elevation is the angle above the horizon:
+ // / - 0 degrees is on the horizon.
+ // / - 90 degrees is straight up.
+ public double getLightElev() {
+ return lightElev;
+ }
+
+ // / Returns the intensity of the light source.
+ // /
+ // / @returns The intensity of the light source.
+ public double getLightIntensity() {
+ return lightIntensity;
+ }
+
+ // / Determines if the light source is enabled.
+ // /
+ // / @returns
+ // / - @a true if the light source is enabled.
+ // / - @a false if the light source is disabled.
+ public boolean isLightEnabled() {
+ return isLightEnabled;
+ }
+
+ // / Determines if noise-map wrapping is enabled.
+ // /
+ // / @returns
+ // / - @a true if noise-map wrapping is enabled.
+ // / - @a false if noise-map wrapping is disabled.
+ // /
+ // / This object requires five points (the initial point and its four
+ // / neighbors) to calculate light shading. If wrapping is enabled,
+ // / and the initial point is on the edge of the noise map, the
+ // / appropriate neighbors that lie outside of the noise map will
+ // / "wrap" to the opposite side(s) of the noise map. Otherwise, the
+ // / appropriate neighbors are cropped to the edge of the noise map.
+ // /
+ // / Enabling wrapping is useful when creating spherical renderings and
+ // / tileable textures
+ public boolean isWrapEnabled() {
+ return isWrapEnabled;
+ }
+
+ // / Sets the background image.
+ // /
+ // / @param backgroundImage The background image.
+ // /
+ // / If a background image has been specified, the Render() method
+ // / blends the pixels from the background image onto the corresponding
+ // / pixels in the destination image. The blending weights are
+ // / determined by the alpha channel in the pixels in the destination
+ // / image.
+ // /
+ // / The destination image must exist throughout the lifetime of this
+ // / object unless another image replaces that image.
+ public void setBackgroundImage(ImageCafe backgroundImage) {
+ this.backgroundImage = backgroundImage;
+ }
+
+ // / Sets the destination image.
+ // /
+ // / @param destImage The destination image.
+ // /
+ // / The destination image will contain the rendered image after a
+ // / successful call to the Render() method.
+ // /
+ // / The destination image must exist throughout the lifetime of this
+ // / object unless another image replaces that image.
+ public void setDestImage(ImageCafe destImage) {
+ this.destImageCafe = destImage;
+ }
+
+ // / Sets the azimuth of the light source, in degrees.
+ // /
+ // / @param lightAzimuth The azimuth of the light source.
+ // /
+ // / The azimuth is the location of the light source around the
+ // / horizon:
+ // / - 0.0 degrees is east.
+ // / - 90.0 degrees is north.
+ // / - 180.0 degrees is west.
+ // / - 270.0 degrees is south.
+ // /
+ // / Make sure the light source is enabled via a call to the
+ // / EnableLight() method before calling the Render() method.
+ public void setLightAzimuth(double lightAzimuth) {
+ this.lightAzimuth = lightAzimuth;
+ this.recalcLightValues = true;
+ }
+
+ // / Sets the brightness of the light source.
+ // /
+ // / @param lightBrightness The brightness of the light source.
+ // /
+ // / Make sure the light source is enabled via a call to the
+ // / EnableLight() method before calling the Render() method.
+ public void setLightBrightness(double lightBrightness) {
+ this.lightBrightness = lightBrightness;
+ this.recalcLightValues = true;
+ }
+
+ // / Sets the color of the light source.
+ // /
+ // / @param lightColor The light color.
+ // /
+ // / Make sure the light source is enabled via a call to the
+ // / EnableLight() method before calling the Render() method.
+ public void setLightColor(ColorCafe lightColor) {
+ this.lightColor = lightColor;
+ }
+
+ // / Sets the contrast of the light source.
+ // /
+ // / @param lightContrast The contrast of the light source.
+ // /
+ // / @pre The specified light contrast is positive.
+ // /
+ // / @throw noise::ExceptionInvalidParam See the preconditions.
+ // /
+ // / The contrast specifies how sharp the boundary is between the
+ // / light-facing areas and the shadowed areas.
+ // /
+ // / The contrast determines the difference between areas in light and
+ // / areas in shadow. Determining the correct contrast amount requires
+ // / some trial and error, but if your application interprets the noise
+ // / map as a height map that has a spatial resolution of @a h meters
+ // / and an elevation resolution of 1 meter, a good contrast amount to
+ // / use is ( 1.0 / @a h ).
+ // /
+ // / Make sure the light source is enabled via a call to the
+ // / EnableLight() method before calling the Render() method.
+ public void setLightContrast(double lightContrast) throws ExceptionInvalidParam {
+ if (lightContrast <= 0.0)
+ throw new ExceptionInvalidParam("Invalid Parameter in RendererImage");
+
+ this.lightContrast = lightContrast;
+ this.recalcLightValues = true;
+ }
+
+ // / Sets the elevation of the light source, in degrees.
+ // /
+ // / @param lightElev The elevation of the light source.
+ // /
+ // / The elevation is the angle above the horizon:
+ // / - 0 degrees is on the horizon.
+ // / - 90 degrees is straight up.
+ // /
+ // / Make sure the light source is enabled via a call to the
+ // / EnableLight() method before calling the Render() method.
+ public void setLightElev(double lightElev) {
+ this.lightElev = lightElev;
+ this.recalcLightValues = true;
+ }
+
+ // / Sets the intensity of the light source.
+ // /
+ // / @returns The intensity of the light source.
+ // /
+ // / A good value for intensity is 2.0.
+ // /
+ // / Make sure the light source is enabled via a call to the
+ // / enableLight() method before calling the render() method.
+ public void setLightIntensity(double lightIntensity) throws ExceptionInvalidParam {
+ if (lightIntensity < 0.0)
+ throw new ExceptionInvalidParam("Invalid Parameter in RendererImage");
+
+ this.lightIntensity = lightIntensity;
+ this.recalcLightValues = true;
+ }
+
+ // / Sets the source noise map.
+ // /
+ // / @param sourceNoiseMap The source noise map.
+ // /
+ // / The destination image must exist throughout the lifetime of this
+ // / object unless another image replaces that image.
+ public void setSourceNoiseMap(NoiseMap sourceNoiseMap) {
+ this.sourceNoiseMap = sourceNoiseMap;
+ }
+
+}
diff --git a/src/libnoiseforjava/util/RendererNormalMap.java b/src/libnoiseforjava/util/RendererNormalMap.java new file mode 100644 index 0000000..c3b648b --- /dev/null +++ b/src/libnoiseforjava/util/RendererNormalMap.java @@ -0,0 +1,316 @@ +/*
+ * Copyright (C) 2003, 2004 Jason Bevins (original libnoise code)
+ * Copyright 2010 Thomas J. Hodge (java port of libnoise)
+ *
+ * This file is part of libnoiseforjava.
+ *
+ * libnoiseforjava is a Java port of the C++ library libnoise, which may be found at
+ * http://libnoise.sourceforge.net/. libnoise was developed by Jason Bevins, who may be
+ * contacted at [email protected] (for great email, take off every 'zig').
+ * Porting to Java was done by Thomas Hodge, who may be contacted at
+ * [email protected] (remove every 'zag').
+ *
+ * libnoiseforjava is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * libnoiseforjava is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * libnoiseforjava. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package libnoiseforjava.util;
+
+import libnoiseforjava.exception.ExceptionInvalidParam;
+
+public class RendererNormalMap
+{
+ /// Renders a normal map from a noise map.
+ ///
+ /// This class renders an image containing the normal vectors from a noise
+ /// map object. This image can then be used as a bump map for a 3D
+ /// application or game.
+ ///
+ /// This class encodes the (x, y, z) components of the normal vector into
+ /// the (red, green, blue) channels of the image. Like any 24-bit
+ /// true-color image, the channel values range from 0 to 255. 0
+ /// represents a normal coordinate of -1.0 and 255 represents a normal
+ /// coordinate of +1.0.
+ ///
+ /// You should also specify the <i>bump height</i> before rendering the
+ /// normal map. The bump height specifies the ratio of spatial resolution
+ /// to elevation resolution. For example, if your noise map has a spatial
+ /// resolution of 30 meters and an elevation resolution of one meter, set
+ /// the bump height to 1.0 / 30.0.
+ ///
+ /// <b>Rendering the normal map</b>
+ ///
+ /// To render the image containing the normal map, perform the following
+ /// steps:
+ /// - Pass a NoiseMap object to the setSourceNoiseMap() method.
+ /// - Pass an ImageCafe object to the setDestImage() method.
+ /// - Call the render() method.
+
+ /// The bump height for the normal map.
+ double bumpHeight;
+
+ /// A flag specifying whether wrapping is enabled.
+ boolean isWrapEnabled;
+
+ /// A pointer to the destination image.
+ ImageCafe destImageCafe;
+
+ /// A pointer to the source noise map.
+ NoiseMap sourceNoiseMap;
+
+
+ public RendererNormalMap () throws ExceptionInvalidParam
+ {
+ bumpHeight = 1.0;
+ isWrapEnabled = false;
+ destImageCafe = new ImageCafe(0,0);
+ sourceNoiseMap = new NoiseMap(0,0);
+ }
+
+ public RendererNormalMap (int height, int width) throws ExceptionInvalidParam
+ {
+ bumpHeight = 1.0;
+ isWrapEnabled = false;
+ destImageCafe = new ImageCafe(height, width);
+ sourceNoiseMap = new NoiseMap(height, width);
+ }
+
+ /// Calculates the normal vector at a given point on the noise map.
+ ///
+ /// @param nc The height of the given point in the noise map.
+ /// @param nr The height of the left neighbor.
+ /// @param nu The height of the up neighbor.
+ /// @param bumpHeight The bump height.
+ ///
+ /// @returns The normal vector represented as a color.
+ ///
+ /// This method encodes the (x, y, z) components of the normal vector
+ /// into the (red, green, blue) channels of the returned color. In
+ /// order to represent the vector as a color, each coordinate of the
+ /// normal is mapped from the -1.0 to 1.0 range to the 0 to 255 range.
+ ///
+ /// The bump height specifies the ratio of spatial resolution to
+ /// elevation resolution. For example, if your noise map has a
+ /// spatial resolution of 30 meters and an elevation resolution of one
+ /// meter, set the bump height to 1.0 / 30.0.
+ ///
+ /// The spatial resolution and elevation resolution are determined by
+ /// the application.
+ public ColorCafe calcNormalColor (double nc, double nr, double nu,
+ double bumpHeight)
+ {
+ // Calculate the surface normal.
+ nc *= bumpHeight;
+ nr *= bumpHeight;
+ nu *= bumpHeight;
+ double ncr = (nc - nr);
+ double ncu = (nc - nu);
+ double d = Math.sqrt ((ncu * ncu) + (ncr * ncr) + 1);
+ double vxc = (nc - nr) / d;
+ double vyc = (nc - nu) / d;
+ double vzc = 1.0 / d;
+
+ // Map the normal range from the (-1.0 .. +1.0) range to the (0 .. 255)
+ // range.
+ int xc, yc, zc;
+ xc = (int) (Math.floor((vxc + 1.0) * 127.5)) & 0xff;
+ yc = (int) (Math.floor((vyc + 1.0) * 127.5)) & 0xff;
+ zc = (int) (Math.floor((vzc + 1.0) * 127.5)) & 0xff;
+
+ // left as example of what was here in case above conversion doesn't work.
+ //zc = (noise::uint8)((noise::uint)((floor)((vzc + 1.0) * 127.5)) & 0xff);
+
+ return new ColorCafe (xc, yc, zc, 255);
+ }
+
+ /// Renders the noise map to the destination image.
+ ///
+ /// @pre setSourceNoiseMap() has been previously called.
+ /// @pre setDestImage() has been previously called.
+ ///
+ /// @post The original contents of the destination image is destroyed.
+ ///
+ /// @throw ExceptionInvalidParam See the preconditions.
+ public void render () throws ExceptionInvalidParam
+ {
+ if ( sourceNoiseMap == null
+ || destImageCafe == null
+ || sourceNoiseMap.getWidth () <= 0
+ || sourceNoiseMap.getHeight () <= 0)
+ throw new ExceptionInvalidParam ("Invalid Parameter in RendererNormalMap");
+
+
+ int width = sourceNoiseMap.getWidth ();
+ int height = sourceNoiseMap.getHeight ();
+
+ for (int y = 0; y < height; y++)
+ {
+ for (int x = 0; x < width; x++)
+ {
+ // Calculate the positions of the current point's right and up
+ // neighbors.
+ int xRightOffset, yUpOffset;
+ if (isWrapEnabled)
+ {
+ if (x == (int)width - 1)
+ xRightOffset = -((int)width - 1);
+ else
+ xRightOffset = 1;
+
+ if (y == (int)height - 1)
+ yUpOffset = -((int)height - 1);
+ else
+ yUpOffset = 1;
+ }
+ else
+ {
+ if (x == (int)width - 1)
+ xRightOffset = 0;
+ else
+ xRightOffset = 1;
+
+ if (y == (int)height - 1)
+ yUpOffset = 0;
+ else
+ yUpOffset = 1;
+
+ }
+
+ // Get the noise value of the current point in the source noise map
+ // and the noise values of its right and up neighbors.
+ double nc = (double)(sourceNoiseMap.getValue(x, y));
+ double nr = (double)(sourceNoiseMap.getValue((x + xRightOffset),y));
+ double nu = (double)(sourceNoiseMap.getValue(x, (y + yUpOffset)));
+
+ // Calculate the normal product.
+ destImageCafe.setValue(x,y, (calcNormalColor (nc, nr, nu, bumpHeight)));
+
+ // Go to the next point.
+ //++pSource;
+ //++pDest;
+ }
+ }
+ }
+
+ /// Enables or disables noise-map wrapping.
+ ///
+ /// @param enable A flag that enables or disables noise-map wrapping.
+ ///
+ /// This object requires three points (the initial point and the right
+ /// and up neighbors) to calculate the normal vector at that point.
+ /// If wrapping is/ enabled, and the initial point is on the edge of
+ /// the noise map, the appropriate neighbors that lie outside of the
+ /// noise map will "wrap" to the opposite side(s) of the noise map.
+ /// Otherwise, the appropriate neighbors are cropped to the edge of
+ /// the noise map.
+ ///
+ /// Enabling wrapping is useful when creating spherical and tileable
+ /// normal maps.
+ public void enableWrap (boolean enable)
+ {
+ isWrapEnabled = enable;
+ }
+
+ /// Returns the bump height.
+ ///
+ /// @returns The bump height.
+ ///
+ /// The bump height specifies the ratio of spatial resolution to
+ /// elevation resolution. For example, if your noise map has a
+ /// spatial resolution of 30 meters and an elevation resolution of one
+ /// meter, set the bump height to 1.0 / 30.0.
+ ///
+ /// The spatial resolution and elevation resolution are determined by
+ /// the application.
+ public double getBumpHeight ()
+ {
+ return bumpHeight;
+ }
+
+ /// Determines if noise-map wrapping is enabled.
+ ///
+ /// @returns
+ /// - @a true if noise-map wrapping is enabled.
+ /// - @a false if noise-map wrapping is disabled.
+ ///
+ /// This object requires three points (the initial point and the right
+ /// and up neighbors) to calculate the normal vector at that point.
+ /// If wrapping is/ enabled, and the initial point is on the edge of
+ /// the noise map, the appropriate neighbors that lie outside of the
+ /// noise map will "wrap" to the opposite side(s) of the noise map.
+ /// Otherwise, the appropriate neighbors are cropped to the edge of
+ /// the noise map.
+ ///
+ /// Enabling wrapping is useful when creating spherical and tileable
+ /// normal maps.
+ public boolean isWrapEnabled ()
+ {
+ return isWrapEnabled;
+ }
+
+ /// Sets the bump height.
+ ///
+ /// @param bumpHeight The bump height.
+ ///
+ /// The bump height specifies the ratio of spatial resolution to
+ /// elevation resolution. For example, if your noise map has a
+ /// spatial resolution of 30 meters and an elevation resolution of one
+ /// meter, set the bump height to 1.0 / 30.0.
+ ///
+ /// The spatial resolution and elevation resolution are determined by
+ /// the application.
+ public void setBumpHeight (double bumpHeight)
+ {
+ this.bumpHeight = bumpHeight;
+ }
+
+ /// Sets the destination image.
+ ///
+ /// @param destImage The destination image.
+ ///
+ /// The destination image will contain the normal map after a
+ /// successful call to the render() method.
+ ///
+ /// The destination image must exist throughout the lifetime of this
+ /// object unless another image replaces that image.
+ public void setDestImage (ImageCafe destImage)
+ {
+ this.destImageCafe = destImage;
+ }
+
+ /// Sets the source noise map.
+ ///
+ /// @param sourceNoiseMap The source noise map.
+ ///
+ /// The destination image must exist throughout the lifetime of this
+ /// object unless another image replaces that image.
+ public void setSourceNoiseMap (NoiseMap sourceNoiseMap)
+ {
+ this.sourceNoiseMap = sourceNoiseMap;
+ }
+
+ public ImageCafe getDestImageCafe()
+ {
+ return destImageCafe;
+ }
+
+ public NoiseMap getSourceNoiseMap()
+ {
+ return sourceNoiseMap;
+ }
+
+ public void setDestImageCafe(ImageCafe destImageCafe)
+ {
+ this.destImageCafe = destImageCafe;
+ }
+
+}
diff --git a/src/ru/olamedia/Options.java b/src/ru/olamedia/Options.java new file mode 100644 index 0000000..e1c4d41 --- /dev/null +++ b/src/ru/olamedia/Options.java @@ -0,0 +1,5 @@ +package ru.olamedia; + +public class Options { + public static int renderDistance = 256; +} diff --git a/src/ru/olamedia/asset/Asset.java b/src/ru/olamedia/asset/Asset.java new file mode 100644 index 0000000..a420c10 --- /dev/null +++ b/src/ru/olamedia/asset/Asset.java @@ -0,0 +1,29 @@ +package ru.olamedia.asset; + +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; + +public class Asset { + protected URL url; + + public boolean inJar() { + return url.toString().startsWith("file:jar:"); + } + + public Asset(URL url) { + this.url = url; + } + + public URL getURL() { + return url; + } + + public InputStream getInputStream() throws IOException { + return url.openStream(); + } + + public String getFile() { + return url.getFile(); + } +} diff --git a/src/ru/olamedia/asset/AssetManager.java b/src/ru/olamedia/asset/AssetManager.java new file mode 100644 index 0000000..d1de11b --- /dev/null +++ b/src/ru/olamedia/asset/AssetManager.java @@ -0,0 +1,28 @@ +package ru.olamedia.asset; + +import java.net.URL; + +public class AssetManager { + + public static URL getBaseURL() { + return AssetManager.class.getResource(AssetManager.class.getSimpleName() + ".class"); + } + + public boolean inJar() { + // file:jar:c:/path/to/jar/somejar.jar! + return getBaseURL().toString().startsWith("file:jar:"); + // return getBaseURL().toString().indexOf(".jar!") > 0; + } + + public static URL getURL(String path) throws AssetNotFoundException { + URL url = AssetManager.class.getClassLoader().getResource(path); + if (null == url) { + throw new AssetNotFoundException(path); + } + return url; + } + + public static Asset getAsset(String path) throws AssetNotFoundException { + return new Asset(getURL(path)); + } +} diff --git a/src/ru/olamedia/asset/AssetNotFoundException.java b/src/ru/olamedia/asset/AssetNotFoundException.java new file mode 100644 index 0000000..29afdf0 --- /dev/null +++ b/src/ru/olamedia/asset/AssetNotFoundException.java @@ -0,0 +1,22 @@ +package ru.olamedia.asset; + +public class AssetNotFoundException extends Exception { + + public AssetNotFoundException() { + super(); + } + + public AssetNotFoundException(String message, Throwable cause) { + super(message, cause); + } + + public AssetNotFoundException(String message) { + super(message); + } + + public AssetNotFoundException(Throwable cause) { + super(cause); + } + + private static final long serialVersionUID = 2197816222986044998L; +} diff --git a/src/ru/olamedia/asset/package-info.java b/src/ru/olamedia/asset/package-info.java new file mode 100644 index 0000000..d2ed4df --- /dev/null +++ b/src/ru/olamedia/asset/package-info.java @@ -0,0 +1,8 @@ +/** + * + */ +/** + * @author olamedia + * + */ +package ru.olamedia.asset;
\ No newline at end of file diff --git a/src/ru/olamedia/camera/CameraProjectionMatrix.java b/src/ru/olamedia/camera/CameraProjectionMatrix.java new file mode 100644 index 0000000..ec1c390 --- /dev/null +++ b/src/ru/olamedia/camera/CameraProjectionMatrix.java @@ -0,0 +1,77 @@ +package ru.olamedia.camera; + +import org.openmali.FastMath; +import org.openmali.vecmath2.Matrix4f; + +public class CameraProjectionMatrix extends Matrix4f { + + /** + * Creates a mesa-style perspective projection transform, that mimics a + * standard, camera-based, view-model. + * + * @param fovy + * specifies the field of view in the y direction, in radians + * @param aspect + * specifies the aspect ratio and thus the field of view in the x + * direction. The aspect ratio is the ratio of x to y, or width + * to height. + * @param zNear + * the distance to the frustum's near clipping plane. This value + * must be positive, (the value -zNear is the location of the + * near clip plane). + * @param zFar + * the distance to the frustum's far clipping plane. + */ + public final void perspectiveMesa(float fovy, float aspect, float zNear, + float zFar) { + final float ymax = zNear * FastMath.tan(fovy); + final float ymin = -ymax; + final float xmin = ymin * aspect; + final float xmax = ymax * aspect; + + // don't call glFrustum() because of error semantics (covglu) + frustumMesa(xmin, xmax, ymin, ymax, zNear, zFar); + } + + /** + * Creates a masa-style perspective projection transform, that mimics a + * standard, camera-based, view-model. The frustum function-call establishes + * a view-model with the eye at the apex of a symmetric view frustum. The + * arguments define the frustum and its associated perspective projection: + * (left, bottom, -near) and (right, top, -near) specify the point on the + * near clipping plane that maps onto the lower-left and upper-right corners + * of the window respectively, assuming the eye is located at (0, 0, 0). + * + * @param left + * the vertical line on the left edge of the near clipping plane + * mapped to the left edge of the graphics window + * @param right + * the vertical line on the right edge of the near clipping plane + * mapped to the right edge of the graphics window + * @param bottom + * the horizontal line on the bottom edge of the near clipping + * plane mapped to the bottom edge of the graphics window + * @param top + * the horizontal line on the top edge of the near + * @param zNear + * the distance to the frustum's near clipping plane. This value + * must be positive, (the value -near is the location of the near + * clip plane). + * @param zFar + * the distance to the frustum's far clipping plane. This value + * must be positive, and must be greater than near. + */ + public final void frustumMesa(float left, float right, float bottom, + float top, float zNear, float zFar) { + final float x = (2.0f * zNear) / (right - left); + final float y = (2.0f * zNear) / (top - bottom); + final float a = (right + left) / (right - left); + final float b = (top + bottom) / (top - bottom); + final float c = -(zFar + zNear) / (zFar - zNear); + final float d = -(2.0f * zFar * zNear) / (zFar - zNear); + + this.set(x, 0f, 0f, 0f, 0f, y, 0f, 0f, a, b, c, -1f, 0f, 0f, d, 0f); + + } + +} diff --git a/src/ru/olamedia/camera/Cameraman.java b/src/ru/olamedia/camera/Cameraman.java new file mode 100644 index 0000000..7dbbcc0 --- /dev/null +++ b/src/ru/olamedia/camera/Cameraman.java @@ -0,0 +1,21 @@ +package ru.olamedia.camera; + +/** + * Cameraman. + * + * @desc Primary purpose is providing eyes level: getCameraY() + * + * @author olamedia + * + */ +public interface Cameraman { + public float getCameraX(); + + public float getCameraY(); + + public float getCameraZ(); + + public void update(float delta); + + public void captureControls(); +} diff --git a/src/ru/olamedia/camera/MatrixCamera.java b/src/ru/olamedia/camera/MatrixCamera.java new file mode 100644 index 0000000..de37fc8 --- /dev/null +++ b/src/ru/olamedia/camera/MatrixCamera.java @@ -0,0 +1,545 @@ +package ru.olamedia.camera; + +import javax.media.opengl.GL2; +import javax.media.opengl.GLAutoDrawable; +import javax.media.opengl.glu.GLU; +import javax.vecmath.Vector3f; +import javax.vecmath.Matrix4f; + +import org.openmali.FastMath; + +import static org.openmali.FastMath.*; + +import ru.olamedia.olacraft.game.Game; +import ru.olamedia.input.Keyboard; +import ru.olamedia.math.Frustum; +import ru.olamedia.olacraft.render.jogl.PlaneRenderer; +import ru.olamedia.olacraft.render.jogl.VectorRenderer; + +import com.jogamp.newt.event.KeyEvent; + +public class MatrixCamera { + protected float fov = 90f; + protected float aspect = 1f; + protected float zNear = 0.1f; + protected float zFar = 1000f; + private boolean isPitchLocked = true; + private float minPitch = -80f; + private float maxPitch = 80f; + public Frustum frustum = new Frustum(); + + private Vector3f position = new Vector3f(); + private float yaw = 0; // around y + private float pitch = 0; + private float roll = 0; + public Matrix4f projectionMatrix = new Matrix4f(); + private Matrix4f translationMatrix = new Matrix4f(); + private Matrix4f xRotationMatrix = new Matrix4f(); + private Matrix4f yRotationMatrix = new Matrix4f(); + private Matrix4f zRotationMatrix = new Matrix4f(); + private Matrix4f rotationMatrix = new Matrix4f(); + public Matrix4f viewMatrix = new Matrix4f(); + public Matrix4f worldMatrix = new Matrix4f(); + + private Vector3f look = new Vector3f(); + private Vector3f right = new Vector3f(); + private Vector3f up = new Vector3f(); + public boolean isFrustumVisible = false; + + @SuppressWarnings("unused") + private org.openmali.vecmath2.Matrix4f matrixToOpenMali(Matrix4f m) { + return new org.openmali.vecmath2.Matrix4f(matrixToTransposeArray(m)); + } + + public void pack() { + if (isAttachedToCameraman) { + position.x = cameraman.getCameraX(); + position.y = cameraman.getCameraY(); + position.z = cameraman.getCameraZ(); + } + + worldMatrix.setIdentity(); + packProjectionMatrix(); + // projectionMatrix.transpose(); + // worldMatrix.mul(projectionMatrix); + translationMatrix.setIdentity(); + translationMatrix.m03 = position.x; + translationMatrix.m13 = position.y - 0.5f; // FIXME y is looking greater + // than it should + translationMatrix.m23 = position.z; + packRotation(); + packView(); + // after view matrix created, retrieve vectors: + viewMatrix.invert(); + viewMatrix.transpose(); + packLookVector(); + packRightVector(); + packUpVector(); + packFrustum(); + // worldMatrix.mul(projectionMatrix, viewMatrix); + // worldMatrix.transpose(); + // // oglViewMatrix.set(viewMatrix); + // // oglViewMatrix.transpose(); + // frustum = FrustumUtil.extractFrustum(worldMatrix); + // Matrix4f vm = new Matrix4f(viewMatrix); + // vm.invert(); + // frustum.compute(matrixToOpenMali(projectionMatrix), + // matrixToOpenMali(vm)); + // ...... + // finally + // ...... + } + + private ru.olamedia.math.Vector3f nearc; + + private void packFrustum() { + float nearD = zNear + (isFrustumVisible ? 0.2f : 0);// zNear; + float farD = zFar - (isFrustumVisible ? 1f : 0);// zFar; + ru.olamedia.math.Vector3f eye = new ru.olamedia.math.Vector3f(position.getX(), position.getY(), position.getZ()); + ru.olamedia.math.Vector3f eyef = eye;// .translate(look, 1f); + nearc = eyef.translate(look, nearD); + ru.olamedia.math.Vector3f farc = eyef.translate(look, farD); + final float tang = FastMath.tan(FastMath.toRad(fov) / 2.0f); + float nh = nearD * tang * (isFrustumVisible ? 0.3f : 1);// zNear * tang; + float nw = nh * aspect * aspect; + float fh = farD * tang * (isFrustumVisible ? 0.5f : 1);// zNear * tang; + float fw = fh * aspect * aspect; + ru.olamedia.math.Vector3f nrb = nearc.translate(right, -nw / 2).translate(up, -nh / 2); + ru.olamedia.math.Vector3f nlb = nearc.translate(right, nw / 2).translate(up, -nh / 2); + @SuppressWarnings("unused") + ru.olamedia.math.Vector3f nrt = nearc.translate(right, -nw / 2).translate(up, nh / 2); + ru.olamedia.math.Vector3f nlt = nearc.translate(right, nw / 2).translate(up, nh / 2); + ru.olamedia.math.Vector3f frb = farc.translate(right, -fw / 2).translate(up, -fh / 2); + ru.olamedia.math.Vector3f flb = farc.translate(right, fw / 2).translate(up, -fh / 2); + ru.olamedia.math.Vector3f frt = farc.translate(right, -fw / 2).translate(up, fh / 2); + ru.olamedia.math.Vector3f flt = farc.translate(right, fw / 2).translate(up, fh / 2); + + frustum.leftPlane.set3Points(nlb, flb, flt); + frustum.leftPlane.n.negate(); + frustum.rightPlane.set3Points(nrb, frt, frb); + // frustum.rightPlane.n.negate(); + frustum.topPlane.set3Points(nlb, frb, flb);// nlt, frt, flt); + // frustum.topPlane.n.negate(); + frustum.bottomPlane.set3Points(frt, nlt, flt); + // frustum.bottomPlane.n.negate(); + frustum.nearPlane.set3Points(nlb, nlt, nrb); + frustum.farPlane.set3Points(flt, flb, frb); + } + + private float[] matrixToTransposeArray(Matrix4f m) { + return new float[] { + // + m.m00, m.m01, m.m02, m.m03,// + m.m10, m.m11, m.m12, m.m13,// + m.m20, m.m21, m.m22, m.m23,// + m.m30, m.m31, m.m32, m.m33,// + }; + } + + private float[] matrixToArray(Matrix4f m) { + return new float[] { + // + m.m00, m.m10, m.m20, m.m30,// + m.m01, m.m11, m.m21, m.m31,// + m.m02, m.m12, m.m22, m.m32,// + m.m03, m.m13, m.m23, m.m33,// + }; + } + + private GLU glu; + + public void setUp(GLAutoDrawable drawable) { + GL2 gl = drawable.getGL().getGL2(); + updateKeyboard(); + updateMouse(); + if (glu == null) { + glu = new GLU(); + } + // gl.glMatrixMode(GL2.GL_PROJECTION); + // gl.glLoadIdentity(); + // glu.gluPerspective(100f, aspect, 0.2, 1000); + loadProjectionMatrix(drawable); + loadViewMatrix(drawable); + + gl.glColor3f(1, 0, 0); + PlaneRenderer.render(frustum.leftPlane, drawable); + gl.glColor3f(1, 1, 0); + PlaneRenderer.render(frustum.rightPlane, drawable); + gl.glColor3f(1, 0, 1); + PlaneRenderer.render(frustum.topPlane, drawable); + gl.glColor3f(1, 1, 1); + PlaneRenderer.render(frustum.bottomPlane, drawable); + + VectorRenderer.render(nearc, frustum.leftPlane.n, drawable); + } + + private void loadViewMatrix(GLAutoDrawable drawable) { + GL2 gl = drawable.getGL().getGL2(); + gl.glMatrixMode(GL2.GL_MODELVIEW); + gl.glLoadTransposeMatrixf(matrixToArray(viewMatrix), 0); + } + + private void loadProjectionMatrix(GLAutoDrawable drawable) { + GL2 gl = drawable.getGL().getGL2(); + gl.glMatrixMode(GL2.GL_PROJECTION); + gl.glLoadTransposeMatrixf(matrixToArray(projectionMatrix), 0); + } + + private void packProjectionMatrix() { + projectionMatrix.setZero(); + final float tang = FastMath.tan(FastMath.toRad(fov) / 2.0f); + final float size = zNear * tang; + float left = -size, right = size, bottom = -size / aspect, top = size / aspect; + // First Column + projectionMatrix.m00 = 2 * zNear / (right - left); + // Second Column + projectionMatrix.m11 = 2 * zNear / (top - bottom); + // Third Column + projectionMatrix.m20 = (right + left) / (right - left); + projectionMatrix.m21 = (top + bottom) / (top - bottom); + projectionMatrix.m22 = -(zFar + zNear) / (zFar - zNear); + projectionMatrix.m23 = -1; + // Fourth Column + projectionMatrix.m32 = -(2 * zFar * zNear) / (zFar - zNear); + } + + private void packRotation() { + xRotationMatrix.rotX(toRad(pitch)); + yRotationMatrix.rotY(toRad(yaw)); + zRotationMatrix.rotZ(toRad(roll)); + + rotationMatrix.setIdentity(); + rotationMatrix.mul(zRotationMatrix); + rotationMatrix.mul(yRotationMatrix); + rotationMatrix.mul(xRotationMatrix); + } + + private void translatePoint(Vector3f point, Vector3f direction, float delta) { + point.x += direction.x * delta; + point.y += direction.y * delta; + point.z += direction.z * delta; + } + + private void translate(Vector3f direction, float delta) { + translatePoint(position, direction, delta); + } + + private void translate(float dx, float dy, float dz) { + translate(right, dx); + translate(up, dy); + translate(look, -dz); + } + + private void packView() { + viewMatrix.setIdentity(); + viewMatrix.mul(translationMatrix); + viewMatrix.mul(rotationMatrix); + + } + + private void packUpVector() { + up.set(viewMatrix.m01, viewMatrix.m11, viewMatrix.m21); + } + + private void packRightVector() { + right.set(viewMatrix.m00, viewMatrix.m10, viewMatrix.m20); + } + + private void packLookVector() { + look.set(viewMatrix.m02, viewMatrix.m12, viewMatrix.m22); + } + + public MatrixCamera() { + right = new Vector3f(1, 0, 0); + up = new Vector3f(0, 1, 0); + look = new Vector3f(0, 0, 1); + isPitchLocked = true; + pack(); + } + + public void captureControls() { + Keyboard.setName("flyForward", KeyEvent.VK_W); + Keyboard.setName("flyBack", KeyEvent.VK_S); + Keyboard.setName("strafeLeft", KeyEvent.VK_A); + Keyboard.setName("strafeRight", KeyEvent.VK_D); + Keyboard.setName("flyUp", KeyEvent.VK_SPACE); + Keyboard.setName("flyDown", KeyEvent.VK_SHIFT); + } + + public void mouseMoved(float dx, float dy) { + yaw += -dx; + pitch += -dy; + yaw = yaw % 360; + pitch = pitch % 360; + } + + public void updateMouse() { + if (isPitchLocked) { + if (pitch < minPitch) { + pitch = minPitch; + } else if (pitch > maxPitch) { + pitch = maxPitch; + } + } + pack(); + } + + public void lockPitch(float min, float max) { + this.minPitch = min; + this.maxPitch = max; + isPitchLocked = true; + } + + public void unlockPitch() { + isPitchLocked = false; + } + + public void updateKeyboard() { + if (isAttachedToCameraman) { + this.cameraman.update(Game.instance.getDelta()); + return; + } + // --- Keyboard + int left = Keyboard.isKeyDown("strafeLeft") ? 1 : 0; + int right = Keyboard.isKeyDown("strafeRight") ? 1 : 0; + int up = Keyboard.isKeyDown("flyForward") ? 1 : 0; + int down = Keyboard.isKeyDown("flyBack") ? 1 : 0; + int flyUp = Keyboard.isKeyDown("flyUp") ? 1 : 0; + int flyDown = Keyboard.isKeyDown("flyDown") ? 1 : 0; + float distance = 4f * 4.5f * Game.instance.getDelta(); // runspeed, m/s + if (up + down + right + left + flyDown + flyUp > 0) { + translate(// + right * distance - left * distance,// + (isAttachedToCameraman ? 0 : flyUp * distance - flyDown * distance),// + up * distance - down * distance// + ); + pack(); + // System.out.println("Moving... " + position.getX() + " " + // + position.getY() + " " + position.getZ()); + } + } + + protected Cameraman cameraman = null; + protected boolean isAttachedToCameraman = false; + protected float distanceFromCameraman = 0; // third-person view / 0 for + protected boolean lookToCameraman = false; // back/front third-person view + + /** + * @return the fov + */ + public float getFov() { + return fov; + } + + /** + * @param fov + * the fov to set + */ + public void setFov(float fov) { + this.fov = fov; + } + + /** + * @return the aspect + */ + public float getAspect() { + return aspect; + } + + /** + * @param aspect + * the aspect to set + */ + public void setAspect(float aspect) { + this.aspect = aspect; + } + + /** + * @return the zNear + */ + public float getzNear() { + return zNear; + } + + /** + * @param zNear + * the zNear to set + */ + public void setzNear(float zNear) { + this.zNear = zNear; + } + + /** + * @return the zFar + */ + public float getzFar() { + return zFar; + } + + /** + * @param zFar + * the zFar to set + */ + public void setzFar(float zFar) { + this.zFar = zFar; + } + + /** + * @return the yaw + */ + public float getYaw() { + return yaw; + } + + /** + * @param yaw + * the yaw to set + */ + public void setYaw(float yaw) { + this.yaw = yaw; + } + + /** + * @return the pitch + */ + public float getPitch() { + return pitch; + } + + /** + * @param pitch + * the pitch to set + */ + public void setPitch(float pitch) { + this.pitch = pitch; + } + + /** + * @return the cameraman + */ + public Cameraman getCameraman() { + return cameraman; + } + + /** + * @param cameraman + * the cameraman to set + */ + public void setCameraman(Cameraman cameraman) { + this.cameraman = cameraman; + } + + /** + * @return the isAttachedToCameraman + */ + public boolean isAttachedToCameraman() { + return isAttachedToCameraman; + } + + /** + * @param isAttachedToCameraman + * the isAttachedToCameraman to set + */ + public void setAttachedToCameraman(boolean isAttachedToCameraman) { + this.isAttachedToCameraman = isAttachedToCameraman; + } + + /** + * @return the distanceFromCameraman + */ + public float getDistanceFromCameraman() { + return distanceFromCameraman; + } + + /** + * @param distanceFromCameraman + * the distanceFromCameraman to set + */ + public void setDistanceFromCameraman(float distanceFromCameraman) { + this.distanceFromCameraman = distanceFromCameraman; + } + + /** + * @return the lookToCameraman + */ + public boolean isLookToCameraman() { + return lookToCameraman; + } + + /** + * @param lookToCameraman + * the lookToCameraman to set + */ + public void setLookToCameraman(boolean lookToCameraman) { + this.lookToCameraman = lookToCameraman; + } + + public void setX(float x) { + position.x = x; + } + + public void setY(float y) { + position.y = y; + } + + public void setZ(float z) { + position.z = z; + } + + public float getX() { + return position.x; + } + + public float getY() { + return position.y; + } + + public float getZ() { + return position.z; + } + + public float[] getViewMatrixArray() { + return matrixToArray(viewMatrix); + } + + public float[] getProjectionMatrixArray() { + return matrixToArray(viewMatrix); + } + + public float getRoll() { + return roll; + } + + public void attachTo(Cameraman player) { + this.cameraman = player; + this.isAttachedToCameraman = true; + this.cameraman.captureControls(); + } + + public void detach() { + this.isAttachedToCameraman = false; + this.captureControls(); + } + + /** + * @return the look + */ + public Vector3f getLook() { + return look; + } + + /** + * @return the right + */ + public Vector3f getRight() { + return right; + } + + /** + * @return the up + */ + public Vector3f getUp() { + return up; + } + +} diff --git a/src/ru/olamedia/camera/package-info.java b/src/ru/olamedia/camera/package-info.java new file mode 100644 index 0000000..7a19b7f --- /dev/null +++ b/src/ru/olamedia/camera/package-info.java @@ -0,0 +1,8 @@ +/** + * + */ +/** + * @author olamedia + * + */ +package ru.olamedia.camera;
\ No newline at end of file diff --git a/src/ru/olamedia/controls/package-info.java b/src/ru/olamedia/controls/package-info.java new file mode 100644 index 0000000..09ce499 --- /dev/null +++ b/src/ru/olamedia/controls/package-info.java @@ -0,0 +1,8 @@ +/** + * + */ +/** + * @author olamedia + * + */ +package ru.olamedia.controls;
\ No newline at end of file diff --git a/src/ru/olamedia/debug/SystemInfo.java b/src/ru/olamedia/debug/SystemInfo.java new file mode 100644 index 0000000..30060a5 --- /dev/null +++ b/src/ru/olamedia/debug/SystemInfo.java @@ -0,0 +1,24 @@ +package ru.olamedia.debug; + +public class SystemInfo { + public static void dump() { + int cpu = Runtime.getRuntime().availableProcessors(); + long maxMemory = Runtime.getRuntime().maxMemory(); + long totalMemory = Runtime.getRuntime().totalMemory(); + long freeMemory = Runtime.getRuntime().freeMemory(); + // String country = System.getProperty("user.country"); + String username = System.getProperty("user.name"); + String os = System.getProperty("os.name"); + String osver = System.getProperty("os.version"); + String arch = System.getProperty("os.arch"); + System.out.println("Hello, " + username + " :)"); + System.out.println("" + os + " " + arch + " " + osver); + System.out + .println("Total CPU: " + cpu + " Memory free/total/max: " + + ((int) Math.floor(freeMemory / (1024 * 1024))) + "/" + + ((int) Math.floor(totalMemory / (1024 * 1024))) + "/" + + ((int) Math.floor(maxMemory / (1024 * 1024)))); + System.out.println(System.getProperty("java.vendor") + " " + System.getProperty("java.version")); + System.out.println(System.getProperty("java.runtime.name") + " " + System.getProperty("java.runtime.version")); + } +} diff --git a/src/ru/olamedia/debug/package-info.java b/src/ru/olamedia/debug/package-info.java new file mode 100644 index 0000000..fbf0e84 --- /dev/null +++ b/src/ru/olamedia/debug/package-info.java @@ -0,0 +1,8 @@ +/** + * + */ +/** + * @author olamedia + * + */ +package ru.olamedia.debug;
\ No newline at end of file diff --git a/src/ru/olamedia/game/ClientGame.java b/src/ru/olamedia/game/ClientGame.java new file mode 100644 index 0000000..1f0eeae --- /dev/null +++ b/src/ru/olamedia/game/ClientGame.java @@ -0,0 +1,13 @@ +package ru.olamedia.game; + +public class ClientGame extends Game { + GameManager manager; + public ClientGame(GameManager manager) { + this.manager = manager; + } + public void pause(){ + // open in-game menu + super.pause(); + manager.start(); + } +} diff --git a/src/ru/olamedia/game/DynamicJList.java b/src/ru/olamedia/game/DynamicJList.java new file mode 100644 index 0000000..f944ba3 --- /dev/null +++ b/src/ru/olamedia/game/DynamicJList.java @@ -0,0 +1,16 @@ +package ru.olamedia.game; + +import javax.swing.DefaultListModel; +import javax.swing.JList; + +public class DynamicJList extends JList { + private static final long serialVersionUID = 8188447632893130182L; + + public DynamicJList() { + super(new DefaultListModel()); + } + + public DefaultListModel getContents() { + return (DefaultListModel) getModel(); + } +} diff --git a/src/ru/olamedia/game/Game.java b/src/ru/olamedia/game/Game.java new file mode 100644 index 0000000..8e04259 --- /dev/null +++ b/src/ru/olamedia/game/Game.java @@ -0,0 +1,25 @@ +package ru.olamedia.game; + +public class Game { + public boolean isRunning = false; + public boolean isPaused = false; + public void dispose(){ + + } + public void start(){ + isRunning = true; + init(); + } + public void pause(){ + isPaused = true; + } + public void resume(){ + isPaused = false; + } + public void finish(){ + isRunning = false; + } + public void init(){ + + } +} diff --git a/src/ru/olamedia/game/GameFrame.java b/src/ru/olamedia/game/GameFrame.java new file mode 100644 index 0000000..e768b63 --- /dev/null +++ b/src/ru/olamedia/game/GameFrame.java @@ -0,0 +1,194 @@ +package ru.olamedia.game; + +import java.awt.Dimension; +import java.awt.Frame; +import java.awt.Image; +import java.awt.Toolkit; +import java.util.ArrayList; +import java.util.List; + +import javax.media.opengl.GLCapabilities; +import javax.media.opengl.GLProfile; +import javax.swing.JFrame; + +import ru.olamedia.asset.AssetManager; +import ru.olamedia.asset.AssetNotFoundException; +import ru.olamedia.input.Keyboard; +import ru.olamedia.input.MouseJail; +import ru.olamedia.olacraft.OlaCraft; + +import jogamp.newt.awt.NewtFactoryAWT; + +import com.jogamp.newt.Display; +import com.jogamp.newt.Screen; +import com.jogamp.newt.awt.NewtCanvasAWT; +import com.jogamp.newt.event.KeyAdapter; +import com.jogamp.newt.event.KeyEvent; +import com.jogamp.newt.opengl.GLWindow; +import com.jogamp.opengl.util.Animator; + +public class GameFrame { + // java.awt.SystemTray + // http://www.oracle.com/technetwork/articles/javase/systemtray-139788.html + + public static GameFrame instance; + + Display display; + Screen screen; + int screenId; + GLProfile glProfile; + GLCapabilities caps; + protected Frame awtFrame; + protected static GLWindow glWindow; + protected static JFrame jFrame; + int width = 854; + int height = 480; + public static Animator animator; + NewtCanvasAWT newtCanvasAWT; + private boolean glMode = false; + + public void initGL() { + if (null == newtCanvasAWT) { + glProfile = GLProfile.get(GLProfile.GL2);// Default(); + // ES2 + caps = new GLCapabilities(glProfile); + caps.setHardwareAccelerated(true); + caps.setDoubleBuffered(true); + caps.setBackgroundOpaque(false); + + display = NewtFactoryAWT.createDisplay(null); + screen = NewtFactoryAWT.createScreen(display, screenId); + glWindow = GLWindow.create(screen, caps);// GLWindow.create(screen, + // caps); + newtCanvasAWT = new NewtCanvasAWT(glWindow); + glWindow.setUndecorated(false); + glWindow.setPointerVisible(true); + glWindow.confinePointer(false); + glWindow.addWindowListener(new QuitAdapter()); + animator = new Animator(glWindow); + animator.setRunAsFastAsPossible(true); // By default there is a + // brief + // pause in the animation + // loop + animator.start(); + glWindow.addMouseListener(MouseJail.instance); + glWindow.addKeyListener(Keyboard.instance); + glWindow.addKeyListener(new KeyAdapter() { + @Override + public void keyReleased(KeyEvent e) { + super.keyReleased(e); + if (e.getKeyCode() == KeyEvent.VK_ESCAPE) { + glWindow.confinePointer(false); + glWindow.setPointerVisible(true); + } + } + }); + // animator.setUpdateFPSFrames(100, System.err); + jFrame.add(newtCanvasAWT); + glWindow.addGLEventListener(GameManager.instance); + } + } + + public void setGLMode() { + if (!glMode) { + initGL(); + glMode = true; + newtCanvasAWT.setVisible(true); + } + } + + public void setUIMode() { + if (glMode) { + glMode = false; + newtCanvasAWT.setVisible(false); + } + } + + public static int getX() { + return jFrame.getX(); + } + + public static int getY() { + return jFrame.getY(); + } + + public static int getWidth() { + if (null == glWindow) { + return jFrame.getWidth(); + } + return glWindow.getWidth(); + } + + public static int getHeight() { + if (null == glWindow) { + return jFrame.getHeight(); + } + return glWindow.getHeight(); + } + + public GameFrame() { + instance = this; + jFrame = new JFrame(); + jFrame.setMinimumSize(new Dimension(200, 200)); + jFrame.setSize(width, height); + jFrame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); + jFrame.setTitle("OlaCraft " + OlaCraft.version); + setIcons(); + // glWindow.setLocation(100, 100); + jFrame.addWindowListener(new QuitAdapter()); + jFrame.setVisible(true); + } + + private void setIcons() { + List<Image> icons = new ArrayList<Image>(); + try { + icons.add(getImage("icon16x16.png")); + icons.add(getImage("icon32x32.png")); + icons.add(getImage("icon64x64.png")); + icons.add(getImage("icon128x128.png")); + icons.add(getImage("icon256x256.png")); + } catch (AssetNotFoundException e1) { + e1.printStackTrace(); + } + // if (!icons.isEmpty()) { + // awtFrame.setIconImage(getImage("icon32x32.png")); + jFrame.setIconImages(icons); + // } + } + + private Image getImage(String filename) throws AssetNotFoundException { + String iconFile = AssetManager.getAsset("ru/olamedia/game/" + filename).getFile(); + return Toolkit.getDefaultToolkit().createImage(iconFile); + } + + public Animator getAnimator() { + return animator; + } + + public static void confinePointer(boolean confine) { + if (glWindow != null) { + glWindow.confinePointer(confine); + } + } + + public static void setPointerVisible(boolean visible) { + if (glWindow != null) { + glWindow.setPointerVisible(visible); + } + } + + public static GLWindow getWindow() { + return glWindow; + } + + public static JFrame getFrame() { + return jFrame; + } + + public void dispose() { + // glWindow.destroy(); + // newtCanvasAWT.destroy(); + jFrame.dispose(); + // System.err.close(); + } +} diff --git a/src/ru/olamedia/game/GameManager.java b/src/ru/olamedia/game/GameManager.java new file mode 100644 index 0000000..f8c05d9 --- /dev/null +++ b/src/ru/olamedia/game/GameManager.java @@ -0,0 +1,165 @@ +package ru.olamedia.game; + +import java.util.Set; + +import javax.media.nativewindow.WindowClosingProtocol.WindowClosingMode; +import javax.media.opengl.DebugGL2ES2; +import javax.media.opengl.GL; +import javax.media.opengl.GL2ES2; +import javax.media.opengl.GLAutoDrawable; +import javax.media.opengl.GLEventListener; + +import ru.olamedia.olacraft.game.Game; +import ru.olamedia.olacraft.network.discovery.DiscoveryThread; +import ru.olamedia.olacraft.render.jogl.DefaultRenderer; +import ru.olamedia.olacraft.render.jogl.IRenderer; +import ru.olamedia.tasks.TaskManager; + + +import com.jogamp.opengl.JoglVersion; + +public class GameManager implements GLEventListener { + public static GameManager instance; + private GameFrame frame; + private ClientGame clientGame; + private ServerGame serverGame; + private IRenderer renderer; + private MainMenu menu; + + public GameManager() { + instance = this; + } + + private void createServerGame() { + if (null == serverGame) { + serverGame = new ServerGame(this); + } + } + + private void createClientGame() { + if (null == clientGame) { + clientGame = new ClientGame(this); + } + } + + public void startServerGame() { + createServerGame(); + serverGame.start(); + } + + public void startClientGame() { + createClientGame(); + clientGame.start(); + } + + public void resumeClientGame() { + createClientGame(); + clientGame.resume(); + } + + public void finishClientGame() { + createClientGame(); + clientGame.finish(); + } + + public void resumeServerGame() { + createServerGame(); + serverGame.resume(); + } + + public void finishServerGame() { + createServerGame(); + clientGame.finish(); + serverGame.dispose(); + } + + private void init() { + this.frame = new GameFrame(); + menu = new MainMenu(); + this.renderer = new DefaultRenderer(); + GameFrame.getFrame().getContentPane().add(menu); + menu.setVisible(true); + GameFrame.getFrame().validate(); + } + + public void start() { + init(); + while (!QuitAdapter.shouldQuit) { + try { + Thread.sleep(100); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + + public void dispose() { + TaskManager.stopAll(); + if (null != Game.server) { + Game.server.dispose(); + } + if (null != Game.client) { + Game.client.dispose(); + } + if (null != GameFrame.animator) { + if (GameFrame.animator.isStarted()) { + GameFrame.animator.stop(); + } + } + frame.dispose(); + // Get all threads + Set<Thread> threadSet = Thread.getAllStackTraces().keySet(); + for (Thread t : threadSet) { + if (t instanceof DiscoveryThread) { + t.interrupt(); + } + } + } + + @Override + public void init(GLAutoDrawable drawable) { + // GLContext.getContext().getGL() + GL2ES2 gl = drawable.getGL().getGL2ES2(); + //drawable.setGL(new DebugGL2ES2(gl)); + System.err.println(JoglVersion.getGLInfo(drawable.getGL(), null)); + System.err.println(Thread.currentThread() + " Chosen GLCapabilities: " + + drawable.getChosenGLCapabilities()); + System.err.println(Thread.currentThread() + " INIT GL IS: " + gl.getClass().getName()); + System.err.println(Thread.currentThread() + " GL_VENDOR: " + gl.glGetString(GL.GL_VENDOR)); + System.err.println(Thread.currentThread() + " GL_RENDERER: " + gl.glGetString(GL.GL_RENDERER)); + System.err.println(Thread.currentThread() + " GL_VERSION: " + gl.glGetString(GL.GL_VERSION)); + System.err.println(Thread.currentThread() + " GL Profile: " + gl.getGLProfile()); + System.err.println(Thread.currentThread() + " GL:" + gl); + System.err.println(Thread.currentThread() + " GL_VERSION=" + gl.glGetString(GL.GL_VERSION)); + renderer.init(drawable); + } + + @Override + public void dispose(GLAutoDrawable drawable) { + // TODO Auto-generated method stub + + } + + @Override + public void display(GLAutoDrawable drawable) { + GL2ES2 gl = drawable.getGL().getGL2ES2(); + gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT); + //gl.glClearColor(0.2f, 0.2f, 0.2f, 1); + renderer.render(drawable); + } + + @Override + public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) { + GL gl = drawable.getGL().getGL2ES2(); + gl.glViewport(0, 0, width, height); + } + + public void showMainMenu() { + menu.setVisible(true); + } + + public void hideMainMenu() { + menu.setVisible(false); + } + +} diff --git a/src/ru/olamedia/game/Launcher.java b/src/ru/olamedia/game/Launcher.java new file mode 100644 index 0000000..7849468 --- /dev/null +++ b/src/ru/olamedia/game/Launcher.java @@ -0,0 +1,17 @@ +package ru.olamedia.game; + +public class Launcher { + + public Launcher() { + } + + /** + * @param args + */ + public static void main(String[] args) { + GameManager manager = new GameManager(); + manager.start(); + manager.dispose(); + } + +} diff --git a/src/ru/olamedia/game/MainMenu.java b/src/ru/olamedia/game/MainMenu.java new file mode 100644 index 0000000..1b3db13 --- /dev/null +++ b/src/ru/olamedia/game/MainMenu.java @@ -0,0 +1,168 @@ +package ru.olamedia.game; + +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.net.InetAddress; + +import javax.swing.JButton; +import javax.swing.JPanel; +import javax.swing.border.Border; +import javax.swing.border.CompoundBorder; +import javax.swing.border.EmptyBorder; +import javax.swing.border.LineBorder; +import javax.swing.event.ListSelectionEvent; +import javax.swing.event.ListSelectionListener; + +import ru.olamedia.olacraft.game.Game; +import ru.olamedia.olacraft.network.ConnectionState; +import ru.olamedia.olacraft.network.ConnectionStateListener; +import ru.olamedia.olacraft.network.discovery.DiscoveryClient; +import ru.olamedia.olacraft.network.discovery.DiscoveryListener; + +public class MainMenu extends JPanel implements ActionListener { + private JButton startButton; + private JButton startServerButton; + private JButton discoveryButton; + private DynamicJList hosts; + private DiscoveryClient discoveryClient = DiscoveryClient.getInstance(); + private Thread discoveryClientThread; + private static final long serialVersionUID = -271797500986576805L; + + private void stylizeButton(JButton b) { + Border line = new LineBorder(Color.BLACK); + Border margin = new EmptyBorder(5, 15, 5, 15); + Border compound = new CompoundBorder(line, margin); + b.setBackground(new Color(1f, 1f, 1f, 0.8f)); + b.setBorder(compound); + } + + private static boolean DEBUG = true; + + @SuppressWarnings("unused") + private void debug(String s) { + if (DEBUG) { + System.out.println("[MainMenu] " + s); + } + } + + public MainMenu() { + setSize(GameFrame.getWidth(), GameFrame.getHeight()); + setOpaque(false); + // setBackground(new Color(0f, 0f, 0f, 0.8f)); + startButton = new JButton(); + startButton.setSize(500, 40); + startButton.setLocation((GameFrame.getWidth() - 500) / 2, 200); + startButton.setText("JOIN GAME"); + startButton.setEnabled(false); + startButton.setActionCommand("connect"); + startButton.addActionListener(this); + stylizeButton(startButton); + startServerButton = new JButton(); + startServerButton.setSize(500, 40); + startServerButton.setLocation((GameFrame.getWidth() - 500) / 2, 260); + startServerButton.setText("START SERVER"); + startServerButton.setActionCommand("start server"); + startServerButton.addActionListener(this); + stylizeButton(startServerButton); + discoveryButton = new JButton(); + discoveryButton.setSize(500, 40); + discoveryButton.setLocation((GameFrame.getWidth() - 500) / 2, 320); + discoveryButton.setText("REFRESH"); + discoveryButton.setActionCommand("discovery lan"); + discoveryButton.addActionListener(this); + stylizeButton(discoveryButton); + hosts = new DynamicJList(); + hosts.setSize(500, 150); + hosts.setLocation((GameFrame.getWidth() - 500) / 2, 10); + hosts.addListSelectionListener(new ListSelectionListener() { + @Override + public void valueChanged(ListSelectionEvent e) { + if (hosts.getContents().isEmpty()) { + Game.client.setHostname("127.0.0.1"); + System.out.println("Selected: none"); + startButton.setEnabled(false); + } else { + String host = (String) hosts.getContents().get(e.getFirstIndex()); + Game.client.setHostname(host); + System.out.println("Selected: " + host); + startButton.setEnabled(true); + } + } + }); + add(hosts); + add(startButton); + add(startServerButton); + add(discoveryButton); + // LAN discover + // InetAddress address = Game.client.discoverHost(54777, 5000); + // System.out.println(address); + setLayout(new BorderLayout()); + validate(); + Game.client.addStateListener(new ConnectionStateListener() { + @Override + public void onChangeState(ConnectionState state) { + // debug("Client ConnectionState changed"); + if (state.isConnected()) { + GameFrame.instance.setGLMode(); + Game.instance.player.captureControls(); + startButton.setText("LEAVE GAME"); + } else { + GameFrame.instance.setUIMode(); + startButton.setText("JOIN GAME"); + } + } + }); + discoveryClient.addHostListener(new DiscoveryListener() { + @Override + public void onHost(InetAddress address) { + if (null == address) { + discoveryButton.setEnabled(true); + } else { + hosts.getContents().addElement(address.getHostAddress()); + } + } + }); + } + + @Override + public void actionPerformed(ActionEvent e) { + String cmd = e.getActionCommand(); + if (cmd.equals("connect")) { + if (null != Game.instance) { + Game.instance = null; + } + Game.instance = new Game(Game.MODE_MULTIPLAYER); + if (Game.client.isConnected()) { + // LEAVE GAME + Game.client.close(); + } else { + Game.client.connect(); + } + Game.instance.start(); + } + if (cmd.equals("start server")) { + startServerButton.setEnabled(false); + if (Game.server.isRunning()) { + Game.server.stop(); + startServerButton.setText("START SERVER"); + startServerButton.setEnabled(true); + } else { + Game.server.start(); + if (Game.server.isRunning()) { + startServerButton.setText("STOP SERVER"); + startServerButton.setEnabled(true); + } else { + startServerButton.setEnabled(true); + } + } + } + if (cmd.equals("discovery lan")) { + discoveryButton.setEnabled(false); + discoveryClientThread = new Thread(DiscoveryClient.getInstance(), "DISCOVERY CLIENT"); + discoveryClientThread.start(); + hosts.getContents().clear(); + } + } +} diff --git a/src/ru/olamedia/game/QuitAdapter.java b/src/ru/olamedia/game/QuitAdapter.java new file mode 100644 index 0000000..8de1e8a --- /dev/null +++ b/src/ru/olamedia/game/QuitAdapter.java @@ -0,0 +1,71 @@ +package ru.olamedia.game; + +import com.jogamp.newt.event.*; + +public class QuitAdapter extends WindowAdapter implements WindowListener, KeyListener, java.awt.event.WindowListener { + public static boolean shouldQuit = false; + + public boolean shouldQuit() { + return shouldQuit; + } + + public void windowDestroyNotify(WindowEvent e) { + System.err.println("QUIT Window " + Thread.currentThread()); + shouldQuit = true; + } + + public void keyTyped(KeyEvent e) { + if (e.getKeyChar() == 'q') { + System.err.println("QUIT Key " + Thread.currentThread()); + shouldQuit = true; + } + } + + public void keyPressed(KeyEvent e) { + } + + public void keyReleased(KeyEvent e) { + } + + @Override + public void windowActivated(java.awt.event.WindowEvent arg0) { + // TODO Auto-generated method stub + + } + + @Override + public void windowClosed(java.awt.event.WindowEvent arg0) { + // TODO Auto-generated method stub + shouldQuit = true; + } + + @Override + public void windowClosing(java.awt.event.WindowEvent arg0) { + System.err.println("QUIT Window " + Thread.currentThread()); + shouldQuit = true; + } + + @Override + public void windowDeactivated(java.awt.event.WindowEvent arg0) { + // TODO Auto-generated method stub + + } + + @Override + public void windowDeiconified(java.awt.event.WindowEvent arg0) { + // TODO Auto-generated method stub + + } + + @Override + public void windowIconified(java.awt.event.WindowEvent arg0) { + // TODO Auto-generated method stub + + } + + @Override + public void windowOpened(java.awt.event.WindowEvent arg0) { + // TODO Auto-generated method stub + + } +} diff --git a/src/ru/olamedia/game/ServerGame.java b/src/ru/olamedia/game/ServerGame.java new file mode 100644 index 0000000..900a93f --- /dev/null +++ b/src/ru/olamedia/game/ServerGame.java @@ -0,0 +1,10 @@ +package ru.olamedia.game; + +public class ServerGame extends Game { + GameManager manager; + + public ServerGame(GameManager manager) { + this.manager = manager; + } + +} diff --git a/src/ru/olamedia/game/icon128x128.png b/src/ru/olamedia/game/icon128x128.png Binary files differnew file mode 100644 index 0000000..3572950 --- /dev/null +++ b/src/ru/olamedia/game/icon128x128.png diff --git a/src/ru/olamedia/game/icon16x16.png b/src/ru/olamedia/game/icon16x16.png Binary files differnew file mode 100644 index 0000000..1e2d694 --- /dev/null +++ b/src/ru/olamedia/game/icon16x16.png diff --git a/src/ru/olamedia/game/icon256x256.png b/src/ru/olamedia/game/icon256x256.png Binary files differnew file mode 100644 index 0000000..441eae8 --- /dev/null +++ b/src/ru/olamedia/game/icon256x256.png diff --git a/src/ru/olamedia/game/icon32x32.png b/src/ru/olamedia/game/icon32x32.png Binary files differnew file mode 100644 index 0000000..78a1277 --- /dev/null +++ b/src/ru/olamedia/game/icon32x32.png diff --git a/src/ru/olamedia/game/icon64x64.png b/src/ru/olamedia/game/icon64x64.png Binary files differnew file mode 100644 index 0000000..34a184b --- /dev/null +++ b/src/ru/olamedia/game/icon64x64.png diff --git a/src/ru/olamedia/game/package-info.java b/src/ru/olamedia/game/package-info.java new file mode 100644 index 0000000..86a2d0d --- /dev/null +++ b/src/ru/olamedia/game/package-info.java @@ -0,0 +1,8 @@ +/** + * + */ +/** + * @author olamedia + * + */ +package ru.olamedia.game;
\ No newline at end of file diff --git a/src/ru/olamedia/geom/DisplayList.java b/src/ru/olamedia/geom/DisplayList.java new file mode 100644 index 0000000..aeaffc7 --- /dev/null +++ b/src/ru/olamedia/geom/DisplayList.java @@ -0,0 +1,39 @@ +package ru.olamedia.geom; + +import javax.media.opengl.GL; +import javax.media.opengl.GL2; +import javax.media.opengl.GLAutoDrawable; + +public class DisplayList { + private GL2 gl; + private int glDL; + + public DisplayList(GL glx) { + gl = glx.getGL2(); + glDL = gl.glGenLists(1); + } + + public void start() { + gl.glNewList(glDL, GL2.GL_COMPILE); + } + + public void stop() { + gl.glEndList(); + } + + public void render() { + gl.glCallList(glDL); + } + + public void destroy() { + gl.glDeleteLists(glDL, 1); + } + + public void begin() { + start(); + } + + public void end() { + stop(); + } +} diff --git a/src/ru/olamedia/geom/Frustum.java b/src/ru/olamedia/geom/Frustum.java new file mode 100644 index 0000000..5428302 --- /dev/null +++ b/src/ru/olamedia/geom/Frustum.java @@ -0,0 +1,11 @@ +package ru.olamedia.geom; + +//import org.openmali.spatial.bodies.Frustum; + +public class Frustum extends org.openmali.spatial.bodies.Frustum { + + public Frustum() { + super(); + } + +} diff --git a/src/ru/olamedia/geom/Mesh.java b/src/ru/olamedia/geom/Mesh.java new file mode 100644 index 0000000..140cc4d --- /dev/null +++ b/src/ru/olamedia/geom/Mesh.java @@ -0,0 +1,346 @@ +package ru.olamedia.geom; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.FloatBuffer; +import java.util.HashMap; + +import javax.media.opengl.GL; +import javax.media.opengl.GL2; +import javax.media.opengl.GL2ES2; +import javax.media.opengl.GLAutoDrawable; +import javax.media.opengl.fixedfunc.GLPointerFunc; + +import com.jogamp.opengl.util.GLArrayDataServer; +import com.jogamp.opengl.util.texture.Texture; + +public class Mesh { + private FloatBuffer buffer; + private float[] data; + private int ptr; + private int vertexCount; + private int vertexPtr; + private float xOffset; + private float yOffset; + private float zOffset; + + private boolean useColor; + private float red = 1f; + private float green = 1f; + private float blue = 1f; + private float alpha = 1f; + + private boolean useTexture; + private float GLTexture; + private float u = 0f; + private float v = 0f; + @SuppressWarnings("unused") + private float uFactor = 1f; + @SuppressWarnings("unused") + private float vFactor = 1f; + + private boolean wireframe = false; + + private static int vertexSize = 10; + + private GLArrayDataServer interleaved; + private HashMap<Integer, Integer> materials = new HashMap<Integer, Integer>(); + private HashMap<Integer, GLArrayDataServer> arrays = new HashMap<Integer, GLArrayDataServer>(); + + public void setTexture(Texture tex) { + if (null != tex) { + setTextureSize(tex.getWidth(), tex.getHeight()); + setGLTexture(tex.getTextureObject(null)); + } + } + + public void setGLTexture(int tex) { + this.GLTexture = tex; + } + + @SuppressWarnings("unused") + private static boolean useVbo = true; + + private static boolean useQuad = true; + private static boolean useDisplayList = false; + private DisplayList DL; + + public Mesh(int size) { + vertexCount = 0; + data = new float[size * vertexSize]; + // data = new float[size * vertexSize]; + vertexPtr = 0; + useTexture = false; + useColor = false; + } + + private static FloatBuffer generateFloatBuffer(int size) { + return ByteBuffer.allocateDirect(size * 4).order(ByteOrder.nativeOrder()).asFloatBuffer(); + } + + /** + * Reallocates an array with a new size, and copies the contents of the old + * array to the new array. + * + * @param oldArray + * the old array, to be reallocated. + * @param newSize + * the new array size. + * @return A new array with the same contents. + */ + private static float[] resizeArray(float[] oldArray, int newSize) { + int oldSize = oldArray.length; + float[] newArray = new float[newSize]; + int preserveLength = Math.min(oldSize, newSize); + if (preserveLength > 0) + System.arraycopy(oldArray, 0, newArray, 0, preserveLength); + return newArray; + } + + public void compact() { + // data = resizeArray(data, vertexCount * vertexSize); + int size = vertexCount * vertexSize; + buffer = generateFloatBuffer(size); + buffer.position(0); + buffer.put(data, 0, size); + data = null; + // calc vertex count for each material + for (int n = 0; n < vertexCount; n++) { + int tex = (int) buffer.get(vertexSize * n + 9); + if (!materials.containsKey(tex)) { + materials.put(tex, 1); + } else { + materials.put(tex, materials.get(tex) + 1); + } + } + for (Integer m : materials.keySet()) { + int matVertCount = materials.get(m); + final GLArrayDataServer interleaved = GLArrayDataServer.createFixedInterleaved(9, GL2.GL_FLOAT, false, + matVertCount, GL.GL_STATIC_DRAW); + interleaved.addFixedSubArray(GLPointerFunc.GL_VERTEX_ARRAY, 3, GL.GL_ARRAY_BUFFER); + interleaved.addFixedSubArray(GLPointerFunc.GL_COLOR_ARRAY, 4, GL.GL_ARRAY_BUFFER); + interleaved.addFixedSubArray(GLPointerFunc.GL_TEXTURE_COORD_ARRAY, 2, GL.GL_ARRAY_BUFFER); + arrays.put(m, interleaved); + } + for (int n = 0; n < vertexCount; n++) { + int m = (int) buffer.get(vertexSize * n + 9); + final GLArrayDataServer interleaved = arrays.get(m); + interleaved.putf(buffer.get(vertexSize * n + 0)); + interleaved.putf(buffer.get(vertexSize * n + 1)); + interleaved.putf(buffer.get(vertexSize * n + 2)); + interleaved.putf(buffer.get(vertexSize * n + 3)); + interleaved.putf(buffer.get(vertexSize * n + 4)); + interleaved.putf(buffer.get(vertexSize * n + 5)); + interleaved.putf(buffer.get(vertexSize * n + 6)); + interleaved.putf(buffer.get(vertexSize * n + 7)); + interleaved.putf(buffer.get(vertexSize * n + 8)); + } + for (Integer m : materials.keySet()) { + final GLArrayDataServer interleaved = arrays.get(m); + interleaved.seal(true); + } + // interleaved.put(buffer); + if (vertexCount > 0) { + // System.out.println(interleaved); + } + /* + * buffer.position(0); + * buffer.limit(size * vertexSize); + * buffer.position(0); + * buffer.limit(vertexCount * vertexSize); + * buffer.compact(); + * buffer.position(0); + */ + } + + public void endMesh() { + compact(); + } + + public void setTranslation(float x, float y, float z) { + xOffset = x; + yOffset = y; + zOffset = z; + } + + public void setPoint3f(float x, float y, float z) { + ptr = vertexPtr * vertexSize; + data[ptr + 0] = x + xOffset; + // buffer.put(x + xOffset); + data[ptr + 1] = y + yOffset; + // buffer.put(y + yOffset); + data[ptr + 2] = z + zOffset; + // buffer.put(z + zOffset); + if (useColor) { + data[ptr + 3] = red; + // buffer.put(red); + data[ptr + 4] = green; + // buffer.put(green); + data[ptr + 5] = blue; + // buffer.put(blue); + data[ptr + 6] = alpha; + // buffer.put(alpha); + } else { + // buffer.put(1f); + // buffer.put(1f); + // buffer.put(1f); + // buffer.put(1f); + } + if (useTexture) { + // buffer.put(GLTexture); + data[ptr + 7] = u;// * uFactor; + // buffer.put(u); + data[ptr + 8] = v;// * vFactor; + data[ptr + 9] = GLTexture; + // buffer.put(v); + } else { + // buffer.put(0f); + // buffer.put(0f); + // buffer.put(0f); + } + vertexPtr++; + vertexCount++; + } + + public void setColor4f(float red, float green, float blue, float alpha) { + this.red = red; + this.green = green; + this.blue = blue; + this.alpha = alpha; + } + + public void useColor() { + useColor = true; + } + + public void useTexture() { + useTexture = true; + } + + public void setUV(float u, float v) { + this.u = u; + this.v = v; + } + + public void setTextureSize(float uSize, float vSize) { + this.uFactor = uSize; + this.vFactor = vSize; + } + + public boolean joglIsVBOAvailable(GLAutoDrawable drawable) { + GL2 gl = drawable.getGL().getGL2(); + return gl.isFunctionAvailable("glGenBuffers") && gl.isFunctionAvailable("glBindBuffer") + && gl.isFunctionAvailable("glBufferData") && gl.isFunctionAvailable("glDeleteBuffers"); + } + + public void joglCreateVBO(GLAutoDrawable drawable) { + @SuppressWarnings("unused") + GL2 gl = drawable.getGL().getGL2(); + // gl.glInterleavedArrays(GL2.GL_T2F_C4F_N3F_V3F, stride, pointer) + + } + + public void joglRender(GL glx) { + if (vertexCount < 1) { + return; + } + GL2 gl; + GL2ES2 es2; + gl = glx.getGL2(); + if (useDisplayList) { + gl.glEnable(GL2.GL_CULL_FACE); + gl.glEnable(GL2.GL_DEPTH_TEST); + } + if (wireframe) { + // Set wireframe mode + gl.glPolygonMode(GL.GL_FRONT_AND_BACK, GL2.GL_LINE); + } else { + gl.glPolygonMode(GL.GL_FRONT_AND_BACK, GL2.GL_FILL); + } + + if (useVbo) { + // es2 = glx.getGL2ES2(); + // gl.glBindBuffer(GL2.GL_ARRAY_BUFFER, data); + + // gl.glBindBuffer(GL2.GL_ARRAY_BUFFER, 0); + // gl.glBindBuffer(GL2.GL_ELEMENT_ARRAY_BUFFER, 0); + for (Integer m : materials.keySet()) { + //final GLArrayDataServer interleaved = arrays.get(m); + arrays.get(m).enableBuffer(gl, true); + gl.glEnable(GL.GL_TEXTURE_2D); + gl.glEnable(GL2.GL_CULL_FACE); + gl.glEnable(GL2.GL_DEPTH_TEST); + gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, GL.GL_NEAREST); + gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, GL.GL_NEAREST_MIPMAP_NEAREST); + gl.glBindTexture(GL.GL_TEXTURE_2D, (int) m); + gl.glDrawArrays(GL2.GL_QUADS, 0, arrays.get(m).getElementCount()); + arrays.get(m).enableBuffer(gl, false); + } + /* + * gl.glEnableClientState(GL2.GL_VERTEX_ARRAY); + * gl.glVertexPointer(3, GL2.GL_FLOAT, 10, buffer); + * gl.glDrawArrays(GL2.GL_QUADS, 0, vertexCount); + * gl.glDisableClientState(GL2.GL_VERTEX_ARRAY); + */ + + } else { + if (useDisplayList) { + if (DL == null) { + DL = new DisplayList(glx); + } else { + gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, GL.GL_NEAREST); + gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, GL.GL_NEAREST_MIPMAP_NEAREST); + DL.render(); + return; + } + DL.begin(); + } + gl.glPushAttrib(GL2.GL_ENABLE_BIT | GL2.GL_POLYGON_BIT | GL2.GL_TEXTURE_BIT); + if (useTexture) { + gl.glEnable(GL.GL_TEXTURE_2D); + gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, GL.GL_NEAREST); + gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, GL.GL_NEAREST_MIPMAP_NEAREST); + } + for (int quadI = 0; quadI < vertexCount / 4; quadI++) { + ptr = (quadI * 4 + 0) * vertexSize; + if (useTexture) { + gl.glBindTexture(GL.GL_TEXTURE_2D, (int) buffer.get(ptr + 9)); + gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, GL.GL_NEAREST); + gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, GL.GL_NEAREST_MIPMAP_NEAREST); + gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_WRAP_S, GL.GL_REPEAT); + gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_WRAP_T, GL.GL_REPEAT); + // gl.glDisable(GL.GL_BLEND); + // gl.glTexParameterf(GL.GL_TEXTURE_2D, + // GL.GL_TEXTURE_MAX_ANISOTROPY_EXT, 0); + } + if (useQuad) { + gl.glBegin(GL2.GL_QUADS); + } else { + gl.glBegin(GL2.GL_TRIANGLE_STRIP); + } + { + for (int i = 0; i < 4; i++) { + int k = (useQuad) ? i : ((i == 2) ? 3 : (i == 3 ? 2 : i)); + ptr = (quadI * 4 + k) * vertexSize; + if (useColor) { + gl.glColor4f(buffer.get(ptr + 3), buffer.get(ptr + 4), buffer.get(ptr + 5), + buffer.get(ptr + 6)); + } + if (useTexture) { + float u = buffer.get(ptr + 7); + float v = buffer.get(ptr + 8); + gl.glTexCoord2f(u, v); + } + gl.glVertex3f(buffer.get(ptr), buffer.get(ptr + 1), buffer.get(ptr + 2)); + } + } + gl.glEnd(); + } + gl.glPopAttrib(); + if (useDisplayList) { + DL.end(); + DL.render(); + } + } + } +} diff --git a/src/ru/olamedia/geom/Quad.java b/src/ru/olamedia/geom/Quad.java new file mode 100644 index 0000000..e3d34dd --- /dev/null +++ b/src/ru/olamedia/geom/Quad.java @@ -0,0 +1,12 @@ +package ru.olamedia.geom; + +public class Quad { + private float[] vertices; + private int vertexCount; + + public void addVertex(float x, float y, float z) { + vertices[vertexCount] = x; + vertices[vertexCount + 1] = y; + vertices[vertexCount + 2] = z; + } +} diff --git a/src/ru/olamedia/geom/SimpleQuadMesh.java b/src/ru/olamedia/geom/SimpleQuadMesh.java new file mode 100644 index 0000000..42cf439 --- /dev/null +++ b/src/ru/olamedia/geom/SimpleQuadMesh.java @@ -0,0 +1,113 @@ +package ru.olamedia.geom; + +public class SimpleQuadMesh extends Mesh { + + public SimpleQuadMesh(int size) { + super(size * 4); + } + + private void addBottomLeftBackVertex() { + setPoint3f(-0.5f, -0.5f, -0.5f); + } + + private void addBottomLeftFrontVertex() { + setPoint3f(-0.5f, -0.5f, 0.5f); + } + + private void addBottomRightBackVertex() { + setPoint3f(0.5f, -0.5f, -0.5f); + } + + private void addBottomRightFrontVertex() { + setPoint3f(0.5f, -0.5f, 0.5f); + } + + private void addTopLeftBackVertex() { + setPoint3f(-0.5f, 0.5f, -0.5f); + } + + private void addTopLeftFrontVertex() { + setPoint3f(-0.5f, 0.5f, 0.5f); + } + + private void addTopRightBackVertex() { + setPoint3f(0.5f, 0.5f, -0.5f); + } + + private void addTopRightFrontVertex() { + setPoint3f(0.5f, 0.5f, 0.5f); + } + + public void addFrontQuad() { + // triangle strip: И + setUV(0, 1); + addTopLeftFrontVertex(); // top left + setUV(0, 0); + addBottomLeftFrontVertex(); // bottom left + setUV(1, 0); + addBottomRightFrontVertex(); // bottom right + setUV(1, 1); + addTopRightFrontVertex(); // top right + } + + public void addBackQuad() { + // triangle strip: И + setUV(0, 1); + addTopRightBackVertex(); + setUV(0, 0); + addBottomRightBackVertex(); + setUV(1, 0); + addBottomLeftBackVertex(); + setUV(1, 1); + addTopLeftBackVertex(); + } + + public void addLeftQuad() { + // triangle strip: И + setUV(0, 1); + addTopLeftBackVertex(); + setUV(0, 0); + addBottomLeftBackVertex(); + setUV(1, 0); + addBottomLeftFrontVertex(); + setUV(1, 1); + addTopLeftFrontVertex(); + } + + public void addRightQuad() { + // triangle strip: И + setUV(0, 1); + addTopRightFrontVertex(); + setUV(0, 0); + addBottomRightFrontVertex(); + setUV(1, 0); + addBottomRightBackVertex(); + setUV(1, 1); + addTopRightBackVertex(); + } + + public void addTopQuad() { + // triangle strip: И + setUV(0, 0); + addTopLeftBackVertex(); + setUV(0, 1); + addTopLeftFrontVertex(); + setUV(1, 1); + addTopRightFrontVertex(); + setUV(1, 0); + addTopRightBackVertex(); + } + + public void addBottomQuad() { + // triangle strip: И + setUV(0, 0); + addBottomLeftFrontVertex(); + setUV(0, 1); + addBottomLeftBackVertex(); + setUV(1, 1); + addBottomRightBackVertex(); + setUV(1, 0); + addBottomRightFrontVertex(); + } + +} diff --git a/src/ru/olamedia/geom/package-info.java b/src/ru/olamedia/geom/package-info.java new file mode 100644 index 0000000..97fe3c5 --- /dev/null +++ b/src/ru/olamedia/geom/package-info.java @@ -0,0 +1,8 @@ +/** + * + */ +/** + * @author olamedia + * + */ +package ru.olamedia.geom;
\ No newline at end of file diff --git a/src/ru/olamedia/input/AWTRobotUtil.java b/src/ru/olamedia/input/AWTRobotUtil.java new file mode 100644 index 0000000..9c6778c --- /dev/null +++ b/src/ru/olamedia/input/AWTRobotUtil.java @@ -0,0 +1,97 @@ +package ru.olamedia.input; + +/** + * Copyright 2010 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ + +import java.lang.reflect.InvocationTargetException; +import java.awt.AWTException; +import java.awt.Component; +import java.awt.Point; +import java.awt.Robot; + +public class AWTRobotUtil { + + private static final int ROBOT_DELAY = 100; // ms + + public static Point getCenterLocation(Object obj, boolean onTitleBarIfWindow) throws InterruptedException, + InvocationTargetException { + Component comp = null; + com.jogamp.newt.Window win = null; + + if (obj instanceof com.jogamp.newt.Window) { + win = (com.jogamp.newt.Window) obj; + } else if (obj instanceof Component) { + comp = (Component) obj; + } else { + throw new RuntimeException("Neither AWT nor NEWT: " + obj); + } + + int x0, y0; + if (null != comp) { + java.awt.Point p0 = comp.getLocationOnScreen(); + java.awt.Rectangle r0 = comp.getBounds(); + if (onTitleBarIfWindow && comp instanceof java.awt.Window) { + java.awt.Window window = (java.awt.Window) comp; + java.awt.Insets insets = window.getInsets(); + y0 = (int) (p0.getY() + insets.top / 2.0 + .5); + } else { + y0 = (int) (p0.getY() + r0.getHeight() / 2.0 + .5); + } + x0 = (int) (p0.getX() + r0.getWidth() / 2.0 + .5); + } else { + javax.media.nativewindow.util.Point p0 = win.getLocationOnScreen(null); + if (onTitleBarIfWindow) { + javax.media.nativewindow.util.InsetsImmutable insets = win.getInsets(); + p0.translate(win.getWidth() / 2, insets.getTopHeight() / 2); + } else { + javax.media.nativewindow.util.InsetsImmutable insets = win.getInsets(); + p0.translate(win.getWidth() / 2, (win.getHeight() - insets.getTopHeight()) / 2); + } + x0 = p0.getX(); + y0 = p0.getY(); + } + + return new Point(x0, y0); + } + + /** + * centerMouse + */ + public static Point centerMouse(Robot robot, Object obj, boolean onTitleBarIfWindow) throws AWTException, + InterruptedException, InvocationTargetException { + + Point p0 = getCenterLocation(obj, onTitleBarIfWindow); + // System.err.println("centerMouse: robot pos: " + p0 + + // ", onTitleBarIfWindow: " + onTitleBarIfWindow); + + robot.mouseMove((int) p0.getX(), (int) p0.getY()); + // robot.delay(ROBOT_DELAY); + return p0; + } + +} diff --git a/src/ru/olamedia/input/KeyListener.java b/src/ru/olamedia/input/KeyListener.java new file mode 100644 index 0000000..8fb5d49 --- /dev/null +++ b/src/ru/olamedia/input/KeyListener.java @@ -0,0 +1,10 @@ +package ru.olamedia.input; + +import com.jogamp.newt.event.KeyEvent; + +public interface KeyListener { + public void onKeyPressed(String name, KeyEvent e); + + public void onKeyReleased(String name, KeyEvent e); + +} diff --git a/src/ru/olamedia/input/Keyboard.java b/src/ru/olamedia/input/Keyboard.java new file mode 100644 index 0000000..6a9ecbd --- /dev/null +++ b/src/ru/olamedia/input/Keyboard.java @@ -0,0 +1,64 @@ +package ru.olamedia.input; + +import java.awt.event.KeyEvent; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.commons.collections.BidiMap; +import org.apache.commons.collections.bidimap.DualHashBidiMap; + +public class Keyboard implements com.jogamp.newt.event.KeyListener { + public static Keyboard instance = new Keyboard(); + private static boolean[] downState = new boolean[256]; + private static BidiMap names = new DualHashBidiMap(); + + public static void setName(String name, int keyCode) { + names.put(name, keyCode); + } + + public static boolean isKeyDown(int keyCode) { + return downState[keyCode]; + } + + public static boolean isKeyDown(String name) { + if (names.containsKey(name)) { + return downState[((Integer) names.get(name)).intValue()]; + } + return false; + } + + private static List<ru.olamedia.input.KeyListener> listeners = new ArrayList<ru.olamedia.input.KeyListener>(); + + public static void attach(ru.olamedia.input.KeyListener l) { + listeners.add(l); + } + + @Override + public void keyPressed(com.jogamp.newt.event.KeyEvent e) { + downState[e.getKeyCode()] = true; + if (names.containsValue(e.getKeyCode())) { + String name = (String) names.getKey(e.getKeyCode()); + for (ru.olamedia.input.KeyListener l : listeners) { + l.onKeyPressed(name, e); + } + } + } + + @Override + public void keyReleased(com.jogamp.newt.event.KeyEvent e) { + downState[e.getKeyCode()] = false; + if (names.containsValue(e.getKeyCode())) { + String name = (String) names.getKey(e.getKeyCode()); + for (ru.olamedia.input.KeyListener l : listeners) { + l.onKeyReleased(name, e); + } + } + } + + @Override + public void keyTyped(com.jogamp.newt.event.KeyEvent arg0) { + // TODO Auto-generated method stub + + } +} diff --git a/src/ru/olamedia/input/MouseJail.java b/src/ru/olamedia/input/MouseJail.java new file mode 100644 index 0000000..bd12b0a --- /dev/null +++ b/src/ru/olamedia/input/MouseJail.java @@ -0,0 +1,113 @@ +package ru.olamedia.input; + +import java.awt.AWTException; +import java.awt.Point; +import java.awt.Robot; +import java.lang.reflect.InvocationTargetException; +import java.util.ArrayList; +import java.util.List; + +import com.jogamp.newt.event.MouseAdapter; +import com.jogamp.newt.event.MouseEvent; + +import ru.olamedia.game.GameFrame; + +public class MouseJail extends MouseAdapter { + public static MouseJail instance = new MouseJail(); + + public MouseJail() { + } + + private static boolean isActive = false; + + /** + * @return the isActive + */ + public static boolean isActive() { + return isActive; + } + + /** + * @param isActive + * the isActive to set + */ + public static void setActive(boolean isActive) { + System.out.println("Mouse jail " + (isActive ? "active" : "not active")); + MouseJail.isActive = isActive; + GameFrame.confinePointer(isActive); + GameFrame.setPointerVisible(!isActive); + } + + @Override + public void mouseClicked(MouseEvent e) { + if (e.isAltDown()) { + setActive(false); + } else { + setActive(true); + } + for (ru.olamedia.input.MouseListener l : listeners) { + l.onMouseClick(); + } + } + + @Override + public void mouseEntered(MouseEvent e) { + System.out.println("Entered"); + + } + + @Override + public void mouseExited(MouseEvent e) { + System.out.println("Exited"); + isActive = false; + if (isActive) { + //moveToCenter(); + } + } + + @Override + public void mousePressed(MouseEvent e) { + + } + + @Override + public void mouseReleased(MouseEvent e) { + + } + + @Override + public void mouseDragged(MouseEvent e) { + onMove(e); + } + + private float sensitivity = 2f; + + private void onMove(MouseEvent e) { + if (isActive) { + int cx = GameFrame.getWidth() / 2; + int cy = GameFrame.getHeight() / 2; + float dx = e.getX() - cx; + float dy = e.getY() - cy; + dx *= sensitivity / 10; + dy *= sensitivity / 10; + // System.out.println("Mouse moved " + " dx:" + dx + " dy:" + dy + // + " x:" + e.getX() + " y:" + e.getY()); + for (ru.olamedia.input.MouseListener l : listeners) { + l.onMouseMove(dx, dy); + } + GameFrame.getWindow().warpPointer(cx, cy); + } + } + + @Override + public void mouseMoved(MouseEvent e) { + onMove(e); + } + + private static List<ru.olamedia.input.MouseListener> listeners = new ArrayList<ru.olamedia.input.MouseListener>(); + + public static void attach(ru.olamedia.input.MouseListener l) { + listeners.add(l); + } + +} diff --git a/src/ru/olamedia/input/MouseListener.java b/src/ru/olamedia/input/MouseListener.java new file mode 100644 index 0000000..3d93d1d --- /dev/null +++ b/src/ru/olamedia/input/MouseListener.java @@ -0,0 +1,6 @@ +package ru.olamedia.input; + +public interface MouseListener { + public void onMouseMove(float dx, float dy); + public void onMouseClick(); +} diff --git a/src/ru/olamedia/input/package-info.java b/src/ru/olamedia/input/package-info.java new file mode 100644 index 0000000..ad3f418 --- /dev/null +++ b/src/ru/olamedia/input/package-info.java @@ -0,0 +1,8 @@ +/** + * + */ +/** + * @author olamedia + * + */ +package ru.olamedia.input;
\ No newline at end of file diff --git a/src/ru/olamedia/liveEntity/LiveEntity.java b/src/ru/olamedia/liveEntity/LiveEntity.java new file mode 100644 index 0000000..ce31108 --- /dev/null +++ b/src/ru/olamedia/liveEntity/LiveEntity.java @@ -0,0 +1,683 @@ +package ru.olamedia.liveEntity; + +import javax.vecmath.Vector3f; + +import com.jogamp.newt.event.KeyEvent; + +import ru.olamedia.camera.Cameraman; +import ru.olamedia.olacraft.game.Game; +import ru.olamedia.olacraft.inventory.Inventory; +import ru.olamedia.olacraft.world.block.Block; +import ru.olamedia.olacraft.world.blockStack.BlockStack; +import ru.olamedia.olacraft.world.blockTypes.GravelBlockType; +import ru.olamedia.input.Keyboard; + +public class LiveEntity implements Cameraman { + private Inventory inventory; // every living entity can have inventory + private float x; + private float y; + private float z; + public Vector3f velocity = new Vector3f(0, 0, 0); + public Vector3f acceleration = new Vector3f(0, 0, 0); + + private float fov = 90f; + private float mouseSpeed = 1.0f; + private float maxLookUp = 80.0f; + private float maxLookDown = -80.0f; + private float maxHeight = 1.9f; + private float cameraLevel = 1.8f; + + private float pitch = 0f; + private float yaw = 0f; + private float roll = 0f; + + private float walkSpeed = 1.3f;// 1.3-1.5 m/s + private float runSpeed = 4.5f;// m/s + + private boolean isWalking = false; + private boolean isRunning = false; + private boolean isSneaking = false; + private boolean isCrouching = false; + private boolean isViewBobbing = true; + private float bob = 0f; + private float hSpeed = runSpeed; // horizontal speed + private float vVelocity = 0f; + + @SuppressWarnings("unused") + private float maxHealthPoints; + private float healthPoints; + public float qD = 0; + public float qInvD = 0; + public boolean inJump = false; + public boolean inFall = false; + public boolean onGround = false; + private float savedX; + private float savedY; + private float savedZ; + private int id; + private int connectionId; + private boolean isPositionChanged = false; + + protected void generateInventory() { + // can be overriden for mobs + for (int i = 0; i <= 9; i++) { + inventory.binded[i] = new BlockStack(new Block(), (int) Math.random() * 64); + inventory.binded[i].block.setType(new GravelBlockType()); + } + } + + public Inventory getInventory() { + if (null == inventory) { + inventory = new Inventory(); + generateInventory(); + } + return inventory; + } + + public float getHSpeed() { + return (hSpeed) * (isCrouching ? 0.4f : 1) * (isSneaking ? 0.5f : 1); + } + + public float getHeight() { + return maxHeight * (isCrouching ? 0.5f : 1) * (isSneaking ? 0.8f : 1); + } + + public float getMaxJumpHeight() { + // ~1.5 for 1.8 + return (float) ((float) (maxHeight * 0.83)) * (isCrouching ? 0.8f : 1f); + } + + /** + * Returns the vertical velocity needed to jump the specified height (based + * on current gravity). Uses the Math.sqrt() function. + */ + public float getJumpVelocity(float jumpHeight) { + // use velocity/acceleration formal: v*v = -2 * a(y-y0) + // (v is jump velocity, a is accel, y-y0 is max height) + return (float) Math.sqrt(2 * Game.client.getWorldInfo().gravity * jumpHeight); + } + + public float getCameraLevel() { + return getHeight() * 0.9f; + } + + public boolean isEmptyUnderFoot() { + return isEmptyBlock(0, -1, 0); + } + + /** + * @param delta + * the elapsed time since the last frame update in seconds + */ + public void updateKeyboard(float delta) { + acceleration.x = 0; + acceleration.y = 0; + acceleration.z = 0; + boolean keyLeft = Keyboard.isKeyDown("playerStrafeLeft"); + boolean keyRight = Keyboard.isKeyDown("playerStrafeRight"); + boolean keyForward = Keyboard.isKeyDown("playerForward"); + boolean keyBack = Keyboard.isKeyDown("playerBack"); + boolean keyJump = Keyboard.isKeyDown("playerJump"); + boolean keySneak = Keyboard.isKeyDown("playerSneak"); + boolean keyCrouch = Keyboard.isKeyDown("playerCrouch"); + + if (keySneak) { + if (!isSneaking) { + isSneaking = true; + if (!applyPosition()) { + isSneaking = false; + } + } + } else { + if (isSneaking) { + isSneaking = false; + if (!applyPosition()) { + isSneaking = true; + } + } + } + if (keyCrouch) { + if (!isCrouching) { + isCrouching = true; + if (!applyPosition()) { + isCrouching = false; + } + } + } else { + if (isCrouching) { + isCrouching = false; + if (!applyPosition()) { // Test if we don't have a block over + // head + isCrouching = true; + } + } + } + isWalking = false; + if ((keyForward && !keyBack) || (keyBack && !keyForward)) { + Vector3f look = Game.instance.camera.getLook(); + acceleration.x += look.x * (keyBack ? 1 : -1) * 1f; + acceleration.y += 0; + acceleration.z += look.z * (keyBack ? 1 : -1) * 1f; + } + if ((keyLeft && !keyRight) || (keyRight && !keyLeft)) { + Vector3f right = Game.instance.camera.getRight(); + acceleration.x += right.x * (keyRight ? 1 : -1) * 1f; + acceleration.y += 0; + acceleration.z += right.z * (keyRight ? 1 : -1) * 1f; + } + // acceleration.normalize(); + float normalSpeed = 4.5f; + acceleration.x *= normalSpeed;// running + acceleration.y *= normalSpeed; + acceleration.z *= normalSpeed; + + // if (inJump) { + // float FPS = (float) (delta / 1); + // float accelY = Game.world.gravity; + // float dt = (float) (delta / 1); // in seconds + // vVelocity -= accelY * dt; + // y += vVelocity * dt; + // if (vVelocity < 0) { + // inFall = true; + // } + // if (vVelocity > 0) { + // if (!keyJump) { + // vVelocity = 0; + // } + // } + // if (!applyPosition()) { + // if (vVelocity > 0) { + // // roof + // vVelocity = 0; + // } else { + // y = underFoot().getY() + 1; + // vVelocity = 0; + // inJump = false; + // inFall = false; + // } + // } + // + // } else { + // if (!inFall) { + // if (inAir()) { + // + // inJump = true; + // inFall = true; + // } + // } + // } + if (!onGround && !inAir()) { + // LANDING + onGround = true; + inJump = false; + velocity.y = 0; + acceleration.y = 0; + y = getJumperBlock().getY() + 1; + } + if (onGround && velocity.length() > 0 && acceleration.length() > 0) { + // BEFORE NEW JUMP + // Check direction changed + float vy = velocity.y; + float ay = acceleration.y; + velocity.y = 0; + acceleration.y = 0; + float dAngle = velocity.angle(acceleration); + float speedLimit = 10; + if (dAngle > 0) { + // changing angle + Vector3f newDirection = new Vector3f(velocity); + newDirection.add(acceleration); + if (newDirection.length() > 0) { + newDirection.normalize(); + newDirection.scale(velocity.length()); + } + velocity.set(newDirection); + // check velocity + if (velocity.length() * Math.cos(dAngle) > speedLimit) { + float deltaSpeed = (float) (velocity.length() * Math.cos(dAngle) - speedLimit); + velocity.scale((1 / velocity.length()) * (velocity.length() - deltaSpeed * 0.7f)); + // velocity.scale((float) (10 / velocity.length() * + // Math.cos(dAngle))); + // velocity.scale((float) (velocity.length() + // - (velocity.length() - (10 / velocity.length() * + // Math.cos(dAngle))) * 0.5f * delta)); + } + } else { + if (velocity.length() > speedLimit) { + float deltaSpeed = (float) (velocity.length() - speedLimit); + velocity.scale((1 / velocity.length()) * (velocity.length() - deltaSpeed * 0.7f)); + } + } + velocity.y = vy; + acceleration.y = ay; + } + if (onGround && keyJump) { + // JUMPING + inJump = true; + onGround = false; + velocity.y = getJumpVelocity(getMaxJumpHeight()); + acceleration.y = velocity.y; + // vVelocity = getJumpVelocity(getMaxJumpHeight()); + System.out.println("Max jump height " + getMaxJumpHeight()); + System.out.println("Starting velocity " + velocity.y); + } + + if (onGround && !inJump) { + if (velocity.length() > normalSpeed) { + velocity.scale(normalSpeed / velocity.length()); + } + // APPLY FRICTION + // Vector3f friction = new Vector3f(velocity); + // friction.negate(); + // friction.scale(friction.length()); + // friction.scale(delta); + // velocity.scale((float) Math.exp(-0.2 * delta)); + // acceleration.scale(friction.length()); + } + + if (velocity.length() > 0 && acceleration.length() > 0) { + qD = Math.abs(velocity.dot(acceleration)) / (velocity.length() * acceleration.length()); + } + + // Vector3f a = new Vector3f(acceleration); + // if (a.length() > 0) { + // a.normalize(); + // } + // + // if (qD > 0) { + // qInvD = (float) Math.acos(qD); + // acceleration.scale(qInvD * 10f); + // } + // if (qD > 10) { + // if (velocity.length() > 0) { + // velocity.normalize(); + // } + // velocity.scale(qD); + // } + // if (qd > 10) { + // qd = 10; + // } + // velocity.set(acceleration); + // if (velocity.length() > 1){ + // velocity.scale(1 / velocity.length()); + // } + // velocity.scale(qd); + + if (!onGround || inAir()) { // 0_o + acceleration.y = -Game.client.getWorldInfo().gravity; + } + + // float qangle = (float) Math.abs(Math.acos(qd)); + // if (qangle > 180){ + // acceleration.scale(10f); + // }else if (qangle > 90){ + // acceleration.scale(5f); + // }else if (qangle > 45){ + // acceleration.scale(2f); + // } + + // Quake-like tricks here... + // Vector3f qa = new Vector3f(acceleration); + // if (qa.length() != 0) { + // qa.scale(1 / qa.length()); + // float qd = acceleration.dot(velocity); + // float qangle = (float) Math.abs(Math.acos(qd)); + // if (qangle > 180) { + // // fast stop + // velocity.x *= 0.5f; + // velocity.z *= 0.5f; + // }else{ + // + // } + // if (qd > 14) { + // velocity.x *= 1 / qd; + // velocity.z *= 1 / qd; + // } + // } + if (onGround && (acceleration.length() == 0)) { + velocity.set(0f, 0f, 0f); + } else { + // acceleration.normalize(); + // Vector3f a = new Vector3f(acceleration); + // a.scale(delta); + + if (velocity.length() == 0) { + velocity.x = acceleration.x; + // velocity.y = acceleration.y; + velocity.z = acceleration.z; + } else { + velocity.x += acceleration.x * delta; + velocity.z += acceleration.z * delta; + velocity.y += acceleration.y * delta; + } + + Vector3f move = new Vector3f(velocity); + move.scale(delta); + float dx = 0; + while (move.x != 0) { + if (move.x > 1) { + dx = 1; + move.x -= 1; + } else if (move.x < -1) { + dx = -1; + move.x += 1; + } else { + dx = move.x; + move.x = 0; + } + x += dx; + if (applyPosition()) { + isWalking = true; + } else { + // full stop + velocity.x = 0; + } + } + float dz = 0; + while (move.z != 0) { + if (move.z > 1) { + dz = 1; + move.z -= 1; + } else if (move.z < -1) { + dz = -1; + move.z += 1; + } else { + dz = move.z; + move.z = 0; + } + z += dz; + if (applyPosition()) { + isWalking = true; + } else { + // full stop + velocity.z = 0; + } + } + float dy = 0; + if (move.y != 0) { + while (move.y != 0) { + if (move.y > 1) { + dy = 1; + move.y -= 1; + } else if (move.y < -1) { + dy = -1; + move.y += 1; + } else { + dy = move.y; + move.y = 0; + } + y += dy; + if (applyPosition()) { + isWalking = true; + } else { + // full stop + velocity.y = 0; + } + } + + } + } + } + + private Block underFoot() { + return getBlock(0, -1, 0); + } + + public boolean isEmptyBlock(int dx, int dy, int dz) { + return Game.client.getWorldProvider().isEmptyBlock((int) x + dx, (int) Math.ceil(y) + dy, (int) z + dz); + } + + public boolean haveBlockUnder(int dy) { + return !isEmptyBlock(0, -dy, 0); + } + + public boolean inAir() { + return !haveBlockUnder(1); + } + + public boolean underJumpHeight() { + return haveBlockUnder(1) || haveBlockUnder(2); + } + + public Block getJumperBlock() { + if (haveBlockUnder(1)) { + return getBlock(0, -1, 0); + } + if (haveBlockUnder(2)) { + return getBlock(0, -2, 0); + } + return null; + } + + private Block getBlock(int dx, int dy, int dz) { + return Game.client.getWorldProvider().getBlock((int) x + dx, (int) Math.ceil(y) + dy, (int) z + dz); + } + + public void backupPosition() { + savedX = x; + savedY = y; + savedZ = z; + } + + public void restorePosition() { + x = savedX; + y = savedY; + z = savedZ; + } + + public boolean hasValidPosition() { + Block foot = getBlock(0, 0, 0); + Block underFoot = getBlock(0, -1, 0); + Block head = getBlock(0, (int) getHeight(), 0); + if (!inJump) { + if (underFoot.isEmpty()) { + // In AIR while normal walking + if (isSneaking) { + // TODO Jumping while Sneaking fixes x,z while jumping + return false; + } + } + } + // Check if we're too near to the wall + float screenPlane = 0.2f; + float screenPlaneVertical = 0.4f; + Block[] headNeighbors = head.getNeighbors(); + for (Block b : headNeighbors) { + if (b.isEmpty()) { + continue; + } + if (b.getX() != head.getX()) { + // LEFT or RIGHT + float testX = b.getX(); + if (testX < head.getX()) { + // LEFT, fixing + testX = head.getX(); + } + float minDistance = Math.abs(testX - getX()); + if (minDistance < screenPlane) { + return false; + } + } + if (b.getY() > head.getY()) { // Upper block + float minDistance = Math.abs(b.getY() - getY() + this.getHeight());// player + // height + if (minDistance < screenPlaneVertical) { + return false; + } + } + + if (b.getZ() != head.getZ()) { + // FRONT OR BACK + float testZ = b.getZ(); + if (testZ < head.getZ()) { + // BACK, fixing + testZ = head.getZ(); + } + float minDistance = Math.abs(testZ - getZ()); + if (minDistance < screenPlane) { + return false; + } + } + } + return foot.isEmpty() && head.isEmpty(); + } + + public boolean applyPosition() { + isPositionChanged = false; + if (hasValidPosition()) { + backupPosition(); + isPositionChanged = true; + return true; + } + restorePosition(); + return false; + } + + public void notifyLocationUpdate() { + // overriden at player class + } + + public void fixPosition() { + float dx = x - savedX; + float dy = y - savedY; + float dz = z - savedZ; + restorePosition(); + if (Math.abs(dx) < 1) { // in a block range + x += dx; + applyPosition(); + } + if (Math.abs(dy) < 1) { // in a block range + y += dy; + applyPosition(); + } + if (Math.abs(dz) < 1) { // in a block range + y += dz; + applyPosition(); + } + } + + @Override + public void update(float delta) { + isPositionChanged = false; + backupPosition(); + onGround = false; + Block below = getBlock(0, -1, 0); + if (y == below.getY() + 1) { + onGround = true; + } + updateKeyboard(delta); + // Check if position is valid + // fixPosition(); + + if (y < -20) { + // spawnAt((int) x, (int) z); + } + pitch = Game.instance.camera.getPitch(); + yaw = Game.instance.camera.getYaw(); + // Game.camera.setRoll(roll); + // saveTrace(); + // if (isWalking && onGround) { + // if (!stepsound.isPlaying()) { + // stepsound.playAsSoundEffect(1f, 0.4f, true); + // } + // } else { + // if (stepsound.isPlaying()) { + // stepsound.stop(); + // } + // } + if (isPositionChanged) { + notifyLocationUpdate(); + } + } + + public void setLocation(float x, float y, float z) { + this.setX(x); + this.setY(y); + this.setZ(z); + } + + public void say(String message) { + + } + + public void die() { + healthPoints = 0; + LiveEntityEvent e = new LiveEntityEvent(this); + e.setType(LiveEntityEvent.ON_DIE); + e.dispatch(); + } + + public void acceptDamage(float amount) { + healthPoints -= amount; + if (healthPoints < 0) { + die(); + } + } + + public float getX() { + return x; + } + + public void setX(float x) { + this.x = x; + } + + public float getY() { + return y; + } + + public void setY(float y) { + this.y = y; + } + + public float getZ() { + return z; + } + + public void setZ(float z) { + this.z = z; + } + + @Override + public float getCameraX() { + return x; + } + + @Override + public float getCameraY() { + return y + getCameraLevel(); + } + + @Override + public float getCameraZ() { + return z; + } + + @Override + public void captureControls() { + System.out.println("Player took controls"); + Keyboard.setName("playerForward", KeyEvent.VK_W); + Keyboard.setName("playerBack", KeyEvent.VK_S); + Keyboard.setName("playerStrafeLeft", KeyEvent.VK_A); + Keyboard.setName("playerStrafeRight", KeyEvent.VK_D); + Keyboard.setName("playerJump", KeyEvent.VK_SPACE); + Keyboard.setName("playerSneak", KeyEvent.VK_SHIFT); + Keyboard.setName("playerCrouch", KeyEvent.VK_CONTROL); + } + + public void setId(int id) { + this.id = id; + } + + public int getId() { + return id; + } + + public int getConnectionId() { + return connectionId; + } + + public void setConnectionId(int connectionId) { + this.connectionId = connectionId; + } +} diff --git a/src/ru/olamedia/liveEntity/LiveEntityEvent.java b/src/ru/olamedia/liveEntity/LiveEntityEvent.java new file mode 100644 index 0000000..5c0ded5 --- /dev/null +++ b/src/ru/olamedia/liveEntity/LiveEntityEvent.java @@ -0,0 +1,31 @@ +package ru.olamedia.liveEntity; + +public class LiveEntityEvent { + public static int ON_DIE; + private Object source; + private int type; + + public LiveEntityEvent(Object source) { + this.setSource(source); + } + + public int getType() { + return type; + } + + public void setType(int type) { + this.type = type; + } + + public Object getSource() { + return source; + } + + public void setSource(Object source) { + this.source = source; + } + + public void dispatch() { + LiveEntityEventDispatcher.dispatch(this); + } +} diff --git a/src/ru/olamedia/liveEntity/LiveEntityEventDispatcher.java b/src/ru/olamedia/liveEntity/LiveEntityEventDispatcher.java new file mode 100644 index 0000000..5d29ae1 --- /dev/null +++ b/src/ru/olamedia/liveEntity/LiveEntityEventDispatcher.java @@ -0,0 +1,7 @@ +package ru.olamedia.liveEntity; + +public class LiveEntityEventDispatcher { + public static void dispatch(LiveEntityEvent e){ + + } +} diff --git a/src/ru/olamedia/liveEntity/package-info.java b/src/ru/olamedia/liveEntity/package-info.java new file mode 100644 index 0000000..9c27733 --- /dev/null +++ b/src/ru/olamedia/liveEntity/package-info.java @@ -0,0 +1,8 @@ +/** + * + */ +/** + * @author olamedia + * + */ +package ru.olamedia.liveEntity;
\ No newline at end of file diff --git a/src/ru/olamedia/math/Box.java b/src/ru/olamedia/math/Box.java new file mode 100644 index 0000000..7b9d968 --- /dev/null +++ b/src/ru/olamedia/math/Box.java @@ -0,0 +1,74 @@ +package ru.olamedia.math; + +public class Box { + private Vector3f low = new Vector3f(); + private Vector3f high = new Vector3f(); + + /** + * @param x + * left + * @param y + * lower + * @param z + * back + * @param x2 + * right + * @param y2 + * higher + * @param z2 + * front + */ + public Box(float x, float y, float z, float x2, float y2, float z2) { + low.x = x; + low.y = y; + low.z = z; + high.x = x2; + high.y = y2; + high.z = z2; + } + + public Vector3f getVertex(int i) { + Vector3f vertex = new Vector3f(low); + if (i > 3) { + // 4, 5, 6, 7 + vertex.z = high.z; + } + if (i % 4 > 1) { + // 0 1 2 3 4 5 6 7 + // 0 1 2 3 0 1 2 3 + // - - + + - - + + + vertex.y = high.y; + } + if (i % 2 > 0) { + // 0 1 2 3 4 5 6 7 + // 0 1 0 1 0 1 0 1 + // - + - + - + - + + vertex.x = high.x; + } + return vertex; + } + + public float getLowerX() { + return low.x; + } + + public float getLowerY() { + return low.y; + } + + public float getLowerZ() { + return low.z; + } + + public float getUpperX() { + return high.x; + } + + public float getUpperY() { + return high.y; + } + + public float getUpperZ() { + return high.z; + } +} diff --git a/src/ru/olamedia/math/Classifier.java b/src/ru/olamedia/math/Classifier.java new file mode 100644 index 0000000..551bcf6 --- /dev/null +++ b/src/ru/olamedia/math/Classifier.java @@ -0,0 +1,8 @@ +package ru.olamedia.math; + +public class Classifier { + // INSIDE > INTERSECT > OUTSIDE + public static int OUTSIDE = 0; + public static int INTERSECT = 1; + public static int INSIDE = 2; +} diff --git a/src/ru/olamedia/math/Frustum.java b/src/ru/olamedia/math/Frustum.java new file mode 100644 index 0000000..e127cc0 --- /dev/null +++ b/src/ru/olamedia/math/Frustum.java @@ -0,0 +1,127 @@ +package ru.olamedia.math; + +public class Frustum { + public Plane topPlane = new Plane(); + public Plane bottomPlane = new Plane(); + public Plane leftPlane = new Plane(); + public Plane rightPlane = new Plane(); + public Plane nearPlane = new Plane(); + public Plane farPlane = new Plane(); + private Plane[] planes = getPlanes(); + + private Plane[] getPlanes() { + return new Plane[] { leftPlane, rightPlane, topPlane, bottomPlane };// , + // topPlane,, + // topPlane + // bottomPlane, + // leftPlane, + // rightPlane, farPlane }; + } + + public Vector3f[] getVertices() { + Vector3f[] v = new Vector3f[8]; + v[0] = topPlane.cross(leftPlane, nearPlane); + v[1] = topPlane.cross(leftPlane, farPlane); + v[2] = topPlane.cross(rightPlane, nearPlane); + v[3] = topPlane.cross(rightPlane, farPlane); + v[4] = bottomPlane.cross(leftPlane, nearPlane); + v[5] = bottomPlane.cross(leftPlane, farPlane); + v[6] = bottomPlane.cross(rightPlane, nearPlane); + v[7] = bottomPlane.cross(rightPlane, farPlane); + return v; + } + + public int test(Box b) { + return quickClassify(b); + // int out, in = 0, result; + // result = Classifier.INSIDE; + // int pc = 5; + // for (int i = 0; i < 5; i++) { + // Plane plane = planes[i]; + // out = 0; + // in = 0; + // for (int k = 0; k < 8 && (in == 0 || out == 0); k++) { + // if (plane.distance(b.getVertex(k)) > 0) { + // out++; + // } else { + // in++; + // } + // } + // if (out == 8) { + // System.out.println(i); + // return Classifier.OUTSIDE; + // } + // } + // if (in < pc) { + // result = Classifier.INTERSECT; + // } + // // for (int i = 0; i < 6; i++) { + // // for (int k = 0; k < 8 && (in == 0 || out == 0); k++) { + // // if (planes[i].distance(b.getVertex(k)) < 0) { + // // out++; + // // } else { + // // in++; + // // } + // // } + // // } + // // if (in < 1) { + // // return Classifier.OUTSIDE; + // // } else if (out > 0) { + // // result = Classifier.INTERSECT; + // // } + // return result; + } + + private static final boolean isPointInside(Plane plane, Vector3f p) { + return (plane.distance(p) <= 0.0f); + } + + @SuppressWarnings("unused") + private final boolean isPointInside(Vector3f p) { + return isPointInside(topPlane, p) && isPointInside(bottomPlane, p) && isPointInside(leftPlane, p) + && isPointInside(rightPlane, p) && isPointInside(nearPlane, p); + } + + /** + * Quick check to see if an orthogonal bounding box is inside the frustum + */ + public final int quickClassify(Box box) { + // If all vertices is outside of at least one of planes + for (Plane p : planes) { + int in = 0; + @SuppressWarnings("unused") + int out = 0; + for (int i = 0; i < 8; i++) { + Vector3f v = box.getVertex(i); + if (p.distance(v) > 0.0f) { + out++; + } else { + in++; + } + } + if (in < 1) { + return (Classifier.OUTSIDE); + } + } + + return (Classifier.INTERSECT); + } + + /* + * (non-Javadoc) + * + * @see java.lang.Object#toString() + */ + @Override + public String toString() { + return "Frustum[\r\n" + // + "Top " + topPlane + "\r\n" + // + "Bottom " + bottomPlane + "\r\n" + // + "Left " + leftPlane + "\r\n" + // + "Right " + rightPlane + "\r\n" + // + "Near " + nearPlane + "\r\n" + // + "Far " + farPlane + "\r\n" + // + "]"; + } + +} diff --git a/src/ru/olamedia/math/FrustumUtil.java b/src/ru/olamedia/math/FrustumUtil.java new file mode 100644 index 0000000..80b01fb --- /dev/null +++ b/src/ru/olamedia/math/FrustumUtil.java @@ -0,0 +1,72 @@ +package ru.olamedia.math; + +public class FrustumUtil { + public static Plane[] extractPlanes(javax.vecmath.Matrix4f m, boolean normalize) { + + Plane[] planes = new Plane[6]; + for (int j = 0; j < 6; j++) { + planes[j] = new Plane(); + } + // Left: [30+00, 31+01, 32+02, 33+03] + + planes[0].n.x = m.m30 + m.m00; + planes[0].n.y = m.m31 + m.m01; + planes[0].n.z = m.m32 + m.m02; + planes[0].d = m.m33 + m.m03; + + // Right: [30-00, 31-01, 32-02, 33-03] + + planes[1].n.x = m.m30 - m.m00; + planes[1].n.y = m.m31 - m.m01; + planes[1].n.z = m.m32 - m.m02; + planes[1].d = m.m33 - m.m03; + + // Bottom: [30+10, 31+11, 32+12, 33+13] + + planes[2].n.x = m.m30 + m.m10; + planes[2].n.y = m.m31 + m.m11; + planes[2].n.z = m.m32 + m.m12; + planes[2].d = m.m33 + m.m13; + + // Top: [30-10, 31-11, 32-12, 33-13] + + planes[3].n.x = m.m30 - m.m10; + planes[3].n.y = m.m31 - m.m11; + planes[3].n.z = m.m32 - m.m12; + planes[3].d = m.m33 - m.m13; + + // Near: [30+20, 31+21, 32+22, 33+23] + + planes[4].n.x = m.m30 + m.m20; + planes[4].n.y = m.m31 + m.m21; + planes[4].n.z = m.m32 + m.m22; + planes[4].d = m.m33 + m.m23; + + // Far: [30-20, 31-21, 32-22, 33-23] + + planes[5].n.x = m.m30 - m.m20; + planes[5].n.y = m.m31 - m.m21; + planes[5].n.z = m.m32 - m.m22; + planes[5].d = m.m33 - m.m23; + + // Normalize + if (normalize) { + for (int i = 0; i < 6; ++i) { + planes[i].normalize(); + } + } + return planes; + } + + public static Frustum extractFrustum(javax.vecmath.Matrix4f m) { + Frustum f = new Frustum(); + Plane[] planes = extractPlanes(m, true); + f.leftPlane.set(planes[0]); + f.rightPlane.set(planes[1]); + f.bottomPlane.set(planes[2]); + f.topPlane.set(planes[3]); + f.nearPlane.set(planes[4]); + f.farPlane.set(planes[5]); + return f; + } +} diff --git a/src/ru/olamedia/math/Halfspace.java b/src/ru/olamedia/math/Halfspace.java new file mode 100644 index 0000000..64834df --- /dev/null +++ b/src/ru/olamedia/math/Halfspace.java @@ -0,0 +1,7 @@ +package ru.olamedia.math; + +public class Halfspace { + public static int NEGATIVE = -1; + public static int ON_PLANE = 0; + public static int POSITIVE = 1; +} diff --git a/src/ru/olamedia/math/Matrix4f.java b/src/ru/olamedia/math/Matrix4f.java new file mode 100644 index 0000000..1ce2eb6 --- /dev/null +++ b/src/ru/olamedia/math/Matrix4f.java @@ -0,0 +1,191 @@ +package ru.olamedia.math; + +import static org.openmali.FastMath.*; + +// 4x4 float matrix, column-major notation +public class Matrix4f { + protected float[] m; + + public Matrix4f() { + m = new float[16]; + } + + public Matrix4f(float[] m) { + this.m = m; + } + + public Matrix4f(javax.vecmath.Matrix4f m2) { + m = new float[16]; + m[0] = m2.m00; + m[1] = m2.m10; + m[2] = m2.m20; + m[3] = m2.m30; + m[4] = m2.m01; + m[5] = m2.m11; + m[6] = m2.m21; + m[7] = m2.m31; + m[8] = m2.m02; + m[9] = m2.m12; + m[10] = m2.m22; + m[11] = m2.m32; + m[12] = m2.m03; + m[13] = m2.m13; + m[14] = m2.m23; + m[15] = m2.m33; + } + + public float[] toFloatArray() { + return m; + } + + public void set(int i, float v) { + m[i] = v; + } + + public float get(int i) { + return m[i]; + } + + public void loadIdentity() { + setIdentity(); + } + + public void setIdentity() { + m[0] = m[5] = m[10] = m[15] = 1.0f; + m[1] = m[2] = m[3] = m[4] = 0.0f; + m[6] = m[7] = m[8] = m[9] = 0.0f; + m[11] = m[12] = m[13] = m[14] = 0.0f; + } + + public static Matrix4f translateMatrix(float x, float y, float z) { + Matrix4f m = new Matrix4f(); + m.setIdentity(); + // Translate slots. + m.set(12, x); + m.set(13, y); + m.set(14, z); + return m; + } + + public static Matrix4f scaleMatrix(float sx, float sy, float sz) { + Matrix4f m = new Matrix4f(); + m.setIdentity(); + // Scale slots. + m.set(0, sx); + m.set(5, sy); + m.set(10, sz); + return m; + } + + public static Matrix4f rotateXMatrix(float degrees) { + float radians = toRad(degrees); + float c = cos(radians); + float s = sin(radians); + Matrix4f m = new Matrix4f(); + m.setIdentity(); + // Rotate X formula. + m.set(5, c); + m.set(6, -s); + m.set(9, s); + m.set(10, c); + return m; + } + + public static Matrix4f rotateYMatrix(float degrees) { + float radians = toRad(degrees); + float c = cos(radians); + float s = sin(radians); + Matrix4f m = new Matrix4f(); + m.setIdentity(); + // Rotate Y formula. + m.set(0, c); + m.set(2, s); + m.set(8, -s); + m.set(10, c); + return m; + } + + public static Matrix4f rotateZMatrix(float degrees) { + float radians = toRad(degrees); + float c = cos(radians); + float s = sin(radians); + Matrix4f m = new Matrix4f(); + m.setIdentity(); + // Rotate Z formula. + m.set(0, c); + m.set(1, s); + m.set(4, -s); + m.set(5, c); + return m; + } + + public Vector3f getUpVector() { + return new Vector3f(m[1], m[5], m[9]); + } + + public Vector3f getLookVector() { // POSITIVE_Z + return new Vector3f(m[2], m[6], m[10]); + } + + public Vector3f getRightVector() { + return new Vector3f(m[0], m[4], m[8]); + } + + public Matrix4f multiply(Matrix4f m) { + return Matrix4fUtil.multiply(this, m); + } + + public void apply(Matrix4f m) { + this.m = multiply(m).toFloatArray(); + } + + public float[] getAngles() { + // TODO check majority + float ax, ay, az; + float cy; + ay = -asin(m[2]); /* Calculate Y-axis angle */ + cy = cos(ay); + ay = toDeg(ay); + float trX, trY; + + if (Math.abs(cy) > 0.005) /* Gimball lock? */ + { + trX = m[10] / cy; /* No, so get X-axis angle */ + trY = -m[6] / cy; + + ax = toDeg(atan2(trY, trX)); + + trX = m[0] / cy; /* Get Z-axis angle */ + trY = -m[1] / cy; + + az = toDeg(atan2(trY, trX)); + } else /* Gimball lock has occurred */ + { + ax = 0; /* Set X-axis angle to zero */ + + trX = m[5]; /* And calculate Z-axis angle */ + trY = m[4]; + + az = toDeg(atan2(trY, trX)); + } + + ax = clamp(ax, 0, 360); /* Clamp all angles to range */ + ay = clamp(ay, 0, 360); + az = clamp(az, 0, 360); + return new float[] { ax, ay, ax }; + } + + private float clamp(float a, float min, float max) { + a = a % max; + return a; + } + + public float c(int column, int row) { + // COLUMN-BASED + return m[column * 4 + row]; + } + + public void set(float[] m) { + this.m = m; + } +} diff --git a/src/ru/olamedia/math/Matrix4fUtil.java b/src/ru/olamedia/math/Matrix4fUtil.java new file mode 100644 index 0000000..46d153e --- /dev/null +++ b/src/ru/olamedia/math/Matrix4fUtil.java @@ -0,0 +1,36 @@ +package ru.olamedia.math; + +public class Matrix4fUtil { + public static Matrix4f multiply(Matrix4f m1, Matrix4f m2) { + return new Matrix4f(multiply(m1.toFloatArray(), m2.toFloatArray())); + } + + // MATRIX MULTIPLICATION + public static float[] multiply(float[] m1, float[] m2) { + float[] result = new float[16]; + // First Column + result[0] = m1[0] * m2[0] + m1[4] * m2[1] + m1[8] * m2[2] + m1[12] * m2[3]; + result[1] = m1[1] * m2[0] + m1[5] * m2[1] + m1[9] * m2[2] + m1[13] * m2[3]; + result[2] = m1[2] * m2[0] + m1[6] * m2[1] + m1[10] * m2[2] + m1[14] * m2[3]; + result[3] = m1[3] * m2[0] + m1[7] * m2[1] + m1[11] * m2[2] + m1[15] * m2[3]; + + // Second Column + result[4] = m1[0] * m2[4] + m1[4] * m2[5] + m1[8] * m2[6] + m1[12] * m2[7]; + result[5] = m1[1] * m2[4] + m1[5] * m2[5] + m1[9] * m2[6] + m1[13] * m2[7]; + result[6] = m1[2] * m2[4] + m1[6] * m2[5] + m1[10] * m2[6] + m1[14] * m2[7]; + result[7] = m1[3] * m2[4] + m1[7] * m2[5] + m1[11] * m2[6] + m1[15] * m2[7]; + + // Third Column + result[8] = m1[0] * m2[8] + m1[4] * m2[9] + m1[8] * m2[10] + m1[12] * m2[11]; + result[9] = m1[1] * m2[8] + m1[5] * m2[9] + m1[9] * m2[10] + m1[13] * m2[11]; + result[10] = m1[2] * m2[8] + m1[6] * m2[9] + m1[10] * m2[10] + m1[14] * m2[11]; + result[11] = m1[3] * m2[8] + m1[7] * m2[9] + m1[11] * m2[10] + m1[15] * m2[11]; + + // Fourth Column + result[12] = m1[0] * m2[12] + m1[4] * m2[13] + m1[8] * m2[14] + m1[12] * m2[15]; + result[13] = m1[1] * m2[12] + m1[5] * m2[13] + m1[9] * m2[14] + m1[13] * m2[15]; + result[14] = m1[2] * m2[12] + m1[6] * m2[13] + m1[10] * m2[14] + m1[14] * m2[15]; + result[15] = m1[3] * m2[12] + m1[7] * m2[13] + m1[11] * m2[14] + m1[15] * m2[15]; + return result; + } +} diff --git a/src/ru/olamedia/math/Plane.java b/src/ru/olamedia/math/Plane.java new file mode 100644 index 0000000..d5cd9d0 --- /dev/null +++ b/src/ru/olamedia/math/Plane.java @@ -0,0 +1,71 @@ +package ru.olamedia.math; + +import static java.lang.Math.sqrt; + +public class Plane { + // normal + public Vector3f n = new Vector3f(); + // distance + public float d; + + public void set(Plane p) { + n.x = p.n.x; + n.y = p.n.y; + n.z = p.n.z; + d = p.d; + } + + public float magnitude() { + return (float) sqrt(n.x * n.x + n.y * n.y + n.z * n.z); + } + + public void normalize() { + float mag = magnitude(); + n.x /= mag; + n.y /= mag; + n.z /= mag; + d /= mag; + } + + public float distance(float x, float y, float z) { + return n.x * x + n.y * y + n.z * z + d; + } + + public float distance(Vector3f point) { + return n.x * point.x + n.y * point.y + n.z * point.z + d; + } + + private float dec(float a) { + return (float) Math.floor(a * 100) / 100; + } + + /* + * (non-Javadoc) + * + * @see java.lang.Object#toString() + */ + @Override + public String toString() { + return "Plane[nx=" + dec(n.x) + ";ny=" + dec(n.y) + ";nz=" + dec(n.z) + ";d=" + dec(d) + "]"; + } + + public Vector3f cross(Plane a, Plane b) { + return n.cross(a.n.cross(b.n)); + } + + public void set3Points(Vector3f va, Vector3f vb, Vector3f vc) { + // A = y1 (z2 - z3) + y2 (z3 - z1) + y3 (z1 - z2) + // B = z1 (x2 - x3) + z2 (x3 - x1) + z3 (x1 - x2) + // C = x1 (y2 - y3) + x2 (y3 - y1) + x3 (y1 - y2) + // - D = x1 (y2 z3 - y3 z2) + x2 (y3 z1 - y1 z3) + x3 (y1 z2 - y2 z1) + Vector3f ab = vb.sub(va); + Vector3f ac = vc.sub(va); + Vector3f vn = ab.cross(ac); + n.set(vn); + n.x = va.y * (vb.z - vc.z) + vb.y * (vc.z - va.z) + vc.y * (va.z - vb.z); + n.y = va.z * (vb.x - vc.x) + vb.z * (vc.x - va.x) + vc.z * (va.x - vb.x); + n.z = va.x * (vb.y - vc.y) + vb.x * (vc.y - va.y) + vc.x * (va.y - vb.y); + d = -(vn.x * va.x + vn.y * va.y + vn.z * va.z); + normalize(); + } +} diff --git a/src/ru/olamedia/math/Quaternion.java b/src/ru/olamedia/math/Quaternion.java new file mode 100644 index 0000000..a263f39 --- /dev/null +++ b/src/ru/olamedia/math/Quaternion.java @@ -0,0 +1,25 @@ +package ru.olamedia.math; + +public class Quaternion { + // identity: + public float x = 0; + public float y = 0; + public float z = 0; + public float w = 1; + + public static Quaternion identity() { + return new Quaternion(); + } + + public Quaternion inverse() { + return QuaternionUtil.inverse(this); + } + + public Quaternion mul(Quaternion q) { + return QuaternionUtil.multiply(this, q); + } + + public float[] toMatrixArray(){ + return QuaternionUtil.toMatrixArray(this); + } +} diff --git a/src/ru/olamedia/math/QuaternionUtil.java b/src/ru/olamedia/math/QuaternionUtil.java new file mode 100644 index 0000000..83ee005 --- /dev/null +++ b/src/ru/olamedia/math/QuaternionUtil.java @@ -0,0 +1,54 @@ +package ru.olamedia.math; + +public class QuaternionUtil { + // QUATERNION INVERSE + public static Quaternion inverse(Quaternion q) { + Quaternion newQ = new Quaternion(); + newQ.w = q.w; + newQ.x = -q.x; + newQ.y = -q.y; + newQ.z = -q.z; + // normalize here + return newQ; + } + + // QUATERNION MULTIPLICATION + public static Quaternion multiply(Quaternion q1, Quaternion q2) { + Quaternion newQ = new Quaternion(); + newQ.w = q1.w * q2.w - q1.x * q2.x - q1.y * q2.y - q1.z * q2.z; + newQ.x = q1.w * q2.x + q1.x * q2.w + q1.y * q2.z - q1.z * q2.y; + newQ.y = q1.w * q2.y - q1.x * q2.z + q1.y * q2.w + q1.z * q2.x; + newQ.z = q1.w * q2.z + q1.x * q2.y - q1.y * q2.x + q1.z * q2.w; + return newQ; + } + + // QUATERNION-TO-MATRIX, COLUMN-MAJOR NOTATION + public static float[] toMatrixArray(Quaternion q) { + float[] matrix = new float[16]; + // First Column + matrix[0] = 1 - 2 * (q.y * q.y + q.z * q.z); + matrix[1] = 2 * (q.x * q.y + q.z * q.w); + matrix[2] = 2 * (q.x * q.z - q.y * q.w); + matrix[3] = 0; + // Second Column + matrix[4] = 2 * (q.x * q.y - q.z * q.w); + matrix[5] = 1 - 2 * (q.x * q.x + q.z * q.z); + matrix[6] = 2 * (q.z * q.y + q.x * q.w); + matrix[7] = 0; + // Third Column + matrix[8] = 2 * (q.x * q.z + q.y * q.w); + matrix[9] = 2 * (q.y * q.z - q.x * q.w); + matrix[10] = 1 - 2 * (q.x * q.x + q.y * q.y); + matrix[11] = 0; + // Fourth Column + matrix[12] = 0; + matrix[13] = 0; + matrix[14] = 0; + matrix[15] = 1; + return matrix; + } + + public static float magnitude(Quaternion qa) { + return (float) (Math.sqrt((double) (qa.w * qa.w + qa.x * qa.x + qa.y * qa.y + qa.z * qa.z))); + } +} diff --git a/src/ru/olamedia/math/TransformMatrix.java b/src/ru/olamedia/math/TransformMatrix.java new file mode 100644 index 0000000..6f2ea9d --- /dev/null +++ b/src/ru/olamedia/math/TransformMatrix.java @@ -0,0 +1,15 @@ +package ru.olamedia.math; + +public class TransformMatrix extends Matrix4f { + public void applyTranslation(Matrix4f m) { + apply(m); + } + + public void applyRotation(Matrix4f m) { + apply(m); + } + + public void applyScale(Matrix4f m) { + apply(m); + } +} diff --git a/src/ru/olamedia/math/Vector3f.java b/src/ru/olamedia/math/Vector3f.java new file mode 100644 index 0000000..b16a356 --- /dev/null +++ b/src/ru/olamedia/math/Vector3f.java @@ -0,0 +1,70 @@ +package ru.olamedia.math; + +public class Vector3f { + public float x; + public float y; + public float z; + + public Vector3f() { + this(0, 0, 0); + } + + public Vector3f(float x, float y, float z) { + this.x = x; + this.y = y; + this.z = z; + } + + public Vector3f(Vector3f vector) { + this(vector.x, vector.y, vector.z); + } + + public float dot(Vector3f v) { + return (x * v.x + y * v.y + z * v.z); + } + + public Vector3f cross(Vector3f n) { + Vector3f r = new Vector3f(y * n.z - z * n.y, z * n.x - x * n.z, x * n.y - y * n.x); + return r; + } + + public Vector3f add(Vector3f n) { + Vector3f r = new Vector3f(x + n.x, y + n.y, z + n.z); + return r; + } + + public Vector3f sub(Vector3f n) { + return add(n.negate()); + } + + public Vector3f negate() { + Vector3f n = new Vector3f(this); + n.x = -n.x; + n.y = -n.y; + n.z = -n.z; + return n; + } + + public Vector3f translate(Vector3f look, float f) { + Vector3f v = new Vector3f(this); + v.x += look.x * f; + v.y += look.y * f; + v.z += look.z * f; + return v; + } + + public Vector3f translate(javax.vecmath.Vector3f look, float f) { + Vector3f v = new Vector3f(this); + v.x += look.x * f; + v.y += look.y * f; + v.z += look.z * f; + return v; + } + + public void set(Vector3f vn) { + x = vn.x; + y = vn.y; + z = vn.z; + } + +} diff --git a/src/ru/olamedia/math/ViewMatrix.java b/src/ru/olamedia/math/ViewMatrix.java new file mode 100644 index 0000000..dad4778 --- /dev/null +++ b/src/ru/olamedia/math/ViewMatrix.java @@ -0,0 +1,111 @@ +package ru.olamedia.math; + +public class ViewMatrix extends Matrix4f { + private Matrix4f translation = new Matrix4f(); + private Matrix4f scale = new Matrix4f(); + private Matrix4f rotation = new Matrix4f(); + private TransformMatrix transform = new TransformMatrix(); + + public ViewMatrix() { + translation.setIdentity(); + scale.setIdentity(); + rotation.setIdentity(); + transform.setIdentity(); + pack(); + } + + public void pack() { + loadIdentity(); + transform.loadIdentity(); + transform.applyScale(scale); + transform.applyRotation(rotation); + transform.applyTranslation(translation); + apply(transform); + @SuppressWarnings("unused") + float[] t = transform.toFloatArray(); + + // this.m[12] = 0; + // this.m[13] = 0; + // this.m[14] = 0; + // Fill translation: + // this.m[3] = -(t[0] * t[12] + t[1] * t[13] + t[2] * t[14]); + // this.m[7] = -(t[4] * t[12] + t[5] * t[13] + t[6] * t[14]); + // this.m[11] = (t[8] * t[12] + t[9] * t[13] + t[10] * t[14]); + // m[12] = -(t[0] * t[12] + t[1] * t[13] + t[2] * t[14]); + // m[13] = -(t[4] * t[12] + t[5] * t[13] + t[6] * t[14]); + // m[14] = (t[8] * t[12] + t[9] * t[13] + t[10] * t[14]); + } + + public float getX() { + return -translation.get(12); + } + + public float getY() { + return -translation.get(13); + } + + public float getZ() { + return -translation.get(14); + } + + /** + * @return the translation + */ + public Matrix4f getTranslation() { + return translation; + } + + /** + * @param translation + * the translation to set + */ + public void setTranslation(Matrix4f translation) { + this.translation = translation; + } + + /** + * @return the scale + */ + public Matrix4f getScale() { + return scale; + } + + /** + * @param scale + * the scale to set + */ + public void setScale(Matrix4f scale) { + this.scale = scale; + } + + /** + * @return the rotation + */ + public Matrix4f getRotation() { + return rotation; + } + + /** + * @param rotation + * the rotation to set + */ + public void setRotation(Matrix4f rotation) { + this.rotation = rotation; + } + + public void rotateX(float degrees) { + setRotation(getRotation().multiply(Matrix4f.rotateXMatrix(degrees))); + } + + public void rotateY(float degrees) { + setRotation(getRotation().multiply(Matrix4f.rotateYMatrix(degrees))); + } + + public void rotateZ(float degrees) { + setRotation(getRotation().multiply(Matrix4f.rotateZMatrix(degrees))); + } + + public Matrix4f getTransform() { + return transform; + } +} diff --git a/src/ru/olamedia/math/package-info.java b/src/ru/olamedia/math/package-info.java new file mode 100644 index 0000000..82b4066 --- /dev/null +++ b/src/ru/olamedia/math/package-info.java @@ -0,0 +1,8 @@ +/** + * + */ +/** + * @author olamedia + * + */ +package ru.olamedia.math;
\ No newline at end of file diff --git a/src/ru/olamedia/olacraft/OlaCraft.java b/src/ru/olamedia/olacraft/OlaCraft.java new file mode 100644 index 0000000..b5b3234 --- /dev/null +++ b/src/ru/olamedia/olacraft/OlaCraft.java @@ -0,0 +1,6 @@ +package ru.olamedia.olacraft; + +public class OlaCraft { + public static String version = "0.1.6"; + +} diff --git a/src/ru/olamedia/olacraft/OlaCraftFrame.java b/src/ru/olamedia/olacraft/OlaCraftFrame.java new file mode 100644 index 0000000..95f1835 --- /dev/null +++ b/src/ru/olamedia/olacraft/OlaCraftFrame.java @@ -0,0 +1,10 @@ +package ru.olamedia.olacraft; + +import ru.olamedia.game.GameFrame; + +public class OlaCraftFrame extends GameFrame { + public OlaCraftFrame() { + super(); + jFrame.setTitle("OlaCraft " + OlaCraft.version); + } +} diff --git a/src/ru/olamedia/olacraft/events/GameEvent.java b/src/ru/olamedia/olacraft/events/GameEvent.java new file mode 100644 index 0000000..94b291c --- /dev/null +++ b/src/ru/olamedia/olacraft/events/GameEvent.java @@ -0,0 +1,32 @@ +package ru.olamedia.olacraft.events; + +public class GameEvent { + public static int GAME_START = GameEventRegistry.get("game.start"); + public static int PLAYER_SPAWN = GameEventRegistry.get("player.spawn"); + private Object source; + private int type; + + public GameEvent(Object source) { + this.setSource(source); + } + + public int getType() { + return type; + } + + public void setType(int type) { + this.type = type; + } + + public Object getSource() { + return source; + } + + public void setSource(Object source) { + this.source = source; + } + + public void dispatch() { + GameEventDispatcher.dispatch(this); + } +} diff --git a/src/ru/olamedia/olacraft/events/GameEventDispatcher.java b/src/ru/olamedia/olacraft/events/GameEventDispatcher.java new file mode 100644 index 0000000..7cae41a --- /dev/null +++ b/src/ru/olamedia/olacraft/events/GameEventDispatcher.java @@ -0,0 +1,22 @@ +package ru.olamedia.olacraft.events; + +import java.util.ArrayList; +import java.util.List; + +public class GameEventDispatcher { + private static List<GameEventListener> listeners = new ArrayList<GameEventListener>(); + + public static void attach(GameEventListener listener) { + listeners.add(listener); + } + + public static void detach(GameEventListener listener) { + listeners.remove(listener); + } + + public static void dispatch(GameEvent e) { + for (GameEventListener l : listeners) { + l.on(e); + } + } +} diff --git a/src/ru/olamedia/olacraft/events/GameEventListener.java b/src/ru/olamedia/olacraft/events/GameEventListener.java new file mode 100644 index 0000000..1ff8185 --- /dev/null +++ b/src/ru/olamedia/olacraft/events/GameEventListener.java @@ -0,0 +1,5 @@ +package ru.olamedia.olacraft.events; + +public interface GameEventListener { + public void on(GameEvent e); +} diff --git a/src/ru/olamedia/olacraft/events/GameEventRegistry.java b/src/ru/olamedia/olacraft/events/GameEventRegistry.java new file mode 100644 index 0000000..a9e1885 --- /dev/null +++ b/src/ru/olamedia/olacraft/events/GameEventRegistry.java @@ -0,0 +1,17 @@ +package ru.olamedia.olacraft.events; + +import java.util.HashMap; + +public class GameEventRegistry { + private static HashMap<String, Integer> map = new HashMap<String, Integer>(); + private static int i = 0; + + public static int get(String name) { + if (map.containsKey(name)) { + return map.get(name); + } + i++; + map.put(name, i); + return i; + } +} diff --git a/src/ru/olamedia/olacraft/events/package-info.java b/src/ru/olamedia/olacraft/events/package-info.java new file mode 100644 index 0000000..2a5a677 --- /dev/null +++ b/src/ru/olamedia/olacraft/events/package-info.java @@ -0,0 +1,8 @@ +/** + * + */ +/** + * @author olamedia + * + */ +package ru.olamedia.olacraft.events;
\ No newline at end of file diff --git a/src/ru/olamedia/olacraft/game/Game.java b/src/ru/olamedia/olacraft/game/Game.java new file mode 100644 index 0000000..0980505 --- /dev/null +++ b/src/ru/olamedia/olacraft/game/Game.java @@ -0,0 +1,106 @@ +package ru.olamedia.olacraft.game; + +import com.jogamp.newt.opengl.GLWindow; + +import ru.olamedia.camera.MatrixCamera; +import ru.olamedia.game.GameFrame; +import ru.olamedia.olacraft.events.GameEvent; +import ru.olamedia.olacraft.network.GameClient; +import ru.olamedia.olacraft.network.GameServer; +import ru.olamedia.olacraft.scene.GameScene; +import ru.olamedia.olacraft.world.dataProvider.AbstractChunkDataProvider; +import ru.olamedia.player.Player; + +public class Game { + public static Game instance = null; + public static int port = 26002; + public static boolean isServerRunning = false; + public static GameServer server = new GameServer(); + public static GameClient client = new GameClient(); + public static Timer timer = new Timer(); + + public MatrixCamera camera; + + public static int MODE_SINGLEPLAYER = 1; + public static int MODE_MULTIPLAYER = 2; + public static int MODE_SERVER = 4; + @SuppressWarnings("unused") + private int mode = 1; + private boolean isRunning = false; + @SuppressWarnings("unused") + // player + public Player player; + + // block world + // private blockWorld; + // live entities (including player and npcs) + // private liveEntities; + public Game() { + this(MODE_SINGLEPLAYER); + } + + public Game(int mode) { + this.mode = mode; + if ((MODE_MULTIPLAYER & mode) > 0) { + if ((MODE_SERVER & mode) > 0) { + // init server + } else { + // init client + } + } + player = new Player(); + camera = new MatrixCamera(); + camera.attachTo(player); + camera.setFov(90); + camera.pack(); + // scene.registerLiveEntity(player); + } + + public void start() { + isRunning = true; + GameEvent e = new GameEvent(null); + e.setType(GameEvent.GAME_START); + e.dispatch(); + } + + // Pause game in single mode + public void pause() { + + } + + public void stop() { + + } + + public boolean isRunning() { + return isRunning; + } + + public void spawnMe(int x, int y, int z) { + player.setLocation(x, y, z); + } + + public void tick() { + timer.update(); + + } + + public static class Display { + public static int getWidth() { + return (int) GameFrame.getWidth(); + } + + public static int getHeight() { + return (int) GameFrame.getHeight(); + } + + public static float getAspect() { + return ((float) getWidth()) / ((float) getHeight()); + } + } + + public float getDelta() { + return (float) timer.getElapsedTime() / 1000; + } + +} diff --git a/src/ru/olamedia/olacraft/game/GameInterface.java b/src/ru/olamedia/olacraft/game/GameInterface.java new file mode 100644 index 0000000..1f02071 --- /dev/null +++ b/src/ru/olamedia/olacraft/game/GameInterface.java @@ -0,0 +1,7 @@ +package ru.olamedia.olacraft.game; + +public class GameInterface { + public void requestSpawn(){ + + } +} diff --git a/src/ru/olamedia/olacraft/game/IGameWrapper.java b/src/ru/olamedia/olacraft/game/IGameWrapper.java new file mode 100644 index 0000000..a4a7ed1 --- /dev/null +++ b/src/ru/olamedia/olacraft/game/IGameWrapper.java @@ -0,0 +1,7 @@ +package ru.olamedia.olacraft.game; + +public interface IGameWrapper { + public void setMyId(int connectionId); + + public void spawn(int connectionId, int x, int y, int z); +} diff --git a/src/ru/olamedia/olacraft/game/LocalGameWrapper.java b/src/ru/olamedia/olacraft/game/LocalGameWrapper.java new file mode 100644 index 0000000..8c19ce6 --- /dev/null +++ b/src/ru/olamedia/olacraft/game/LocalGameWrapper.java @@ -0,0 +1,17 @@ +package ru.olamedia.olacraft.game; + +public class LocalGameWrapper implements IGameWrapper { + + @Override + public void setMyId(int connectionId) { + // TODO Auto-generated method stub + + } + + @Override + public void spawn(int connectionId, int x, int y, int z) { + // TODO Auto-generated method stub + + } + +} diff --git a/src/ru/olamedia/olacraft/game/SpawnLocation.java b/src/ru/olamedia/olacraft/game/SpawnLocation.java new file mode 100644 index 0000000..2ff0c39 --- /dev/null +++ b/src/ru/olamedia/olacraft/game/SpawnLocation.java @@ -0,0 +1,7 @@ +package ru.olamedia.olacraft.game; + +public class SpawnLocation { + public int x; + public int y; + public int z; +} diff --git a/src/ru/olamedia/olacraft/game/Timer.java b/src/ru/olamedia/olacraft/game/Timer.java new file mode 100644 index 0000000..1c0aaee --- /dev/null +++ b/src/ru/olamedia/olacraft/game/Timer.java @@ -0,0 +1,99 @@ +package ru.olamedia.olacraft.game; + +/** + * For frame-rate independent movement + * + * @author Oskar Veerhoek + */ +public class Timer { + private long lastTime; // nanoseconds + private double elapsedTime; + private float fps; + private int fpsCounter = 0; + private long lastFPS; + private float avgSeconds = 3; + + /** + * @return the fps + */ + public float getFps() { + return fps; + } + + /** + * @return the avgFps + */ + public float getAvgFps() { + return avgFps; + } + + private float avgFps; + + /** + * Creates a timer. + */ + public Timer() { + fps = 0; + } + + /** + * Initializes the timer. Call this just before entering the game loop. + */ + public void initialize() { + lastTime = System.nanoTime(); + } + + /** + * @return the elapsed time since the the next to last update call + */ + public double getElapsedTime() { + return elapsedTime; + } + + /** + * Updates the timer. Call this once every iteration of the game loop. + * + * @return the elapsed time in milliseconds + */ + public double update() { + if (lastTime == 0) { + lastTime = System.nanoTime(); + return 0; + } else { + long elapsedTime = System.nanoTime() - lastTime; + updateFps(elapsedTime); + lastTime = System.nanoTime(); + this.elapsedTime = elapsedTime / (double) 1000000; + return this.elapsedTime; + } + } + + public void updateFps(long elapsedTime) { + if (elapsedTime > 0) { + float ms = (float) (elapsedTime / 1000000); + if (ms > 0) { + fps = (float) (1000 / ms); + } + } + fpsCounter++; + if (lastFPS == 0) { + lastFPS = System.nanoTime(); + } else { + double elapsedFPS = (System.nanoTime() - lastFPS) / (double) 1000000; + if (elapsedFPS > 1000 * avgSeconds) { + avgFps = fpsCounter / avgSeconds; + fpsCounter = 0; + lastFPS = System.nanoTime(); + } + } + + // if (elapsedTime > 0) { + // fps = (float) (1000 / (elapsedTime / 1000000)); + // if (avgFps == 0) { + // avgFps = fps; + // } else { + // avgFps = avgFps + (fps - avgFps) / 1000; + // } + // } + } +}
\ No newline at end of file diff --git a/src/ru/olamedia/olacraft/game/package-info.java b/src/ru/olamedia/olacraft/game/package-info.java new file mode 100644 index 0000000..85b0f16 --- /dev/null +++ b/src/ru/olamedia/olacraft/game/package-info.java @@ -0,0 +1,8 @@ +/** + * + */ +/** + * @author olamedia + * + */ +package ru.olamedia.olacraft.game;
\ No newline at end of file diff --git a/src/ru/olamedia/olacraft/inventory/Frame.java b/src/ru/olamedia/olacraft/inventory/Frame.java new file mode 100644 index 0000000..a5cd979 --- /dev/null +++ b/src/ru/olamedia/olacraft/inventory/Frame.java @@ -0,0 +1,44 @@ +package ru.olamedia.olacraft.inventory; + +import org.olamedia.olacraft.draw.DrawInterface; +import org.olamedia.olacraft.entity.AbstractEntity; + +import static org.olamedia.olacraft.blocks.Block.BLOCK_SIZE; +import org.olamedia.olacraft.util.CommonApi; + +public class Frame extends AbstractEntity implements DrawInterface { + public Frame(double x, double y, double z, double width, double height, + double depth) { + super(x, y, z, width, height, depth); + } + + public CommonApi api = CommonApi.instance; + + @Override + public void update(double delta) { + + } + + @Override + public void draw() { + api.draw.texRecti("inventory_frame", x, y, BLOCK_SIZE, BLOCK_SIZE); + return; + // Texture t = api.texture.get("inventory_frame"); + // t.bind(); + // glColor3f(1, 1, 1); + // glLoadIdentity(); + // glTranslated(x, y, 0); + // glBegin(GL_QUADS); + // glTexCoord2f(0, 0); + // glVertex2f(0, 0); // Upper-left + // glTexCoord2f(1, 0); + // glVertex2f(BLOCK_SIZE, 0); // Upper-right + // glTexCoord2f(1, 1); + // glVertex2f(BLOCK_SIZE, BLOCK_SIZE); // Bottom-right + // glTexCoord2f(0, 1); + // glVertex2f(0, BLOCK_SIZE); // Bottom-left + // glEnd(); + // glLoadIdentity(); + } + +} diff --git a/src/ru/olamedia/olacraft/inventory/Inventory.java b/src/ru/olamedia/olacraft/inventory/Inventory.java new file mode 100644 index 0000000..2ce843b --- /dev/null +++ b/src/ru/olamedia/olacraft/inventory/Inventory.java @@ -0,0 +1,76 @@ +package ru.olamedia.olacraft.inventory; + +import ru.olamedia.olacraft.world.block.Block; +import ru.olamedia.olacraft.world.blockStack.BlockStack; + +public class Inventory { + public static int BIND_NUM = 10; + public BlockStack[] binded = new BlockStack[BIND_NUM]; + public BlockStack selected; + public int selectedId; + private boolean isInventoryGUIOpen = false; + + public Inventory() { + } + + public void init() { + for (int i = 0; i < BIND_NUM; i++) { + Block block = new Block(x + bindedWrapperPadding + i * BLOCK_SIZE + bindedSpacing * i, y + + bindedWrapperPadding + 0, 0, "gravel"); + binded[i] = new BlockStack(block, 64); + } + binded[0].block.setName("dirt"); + binded[1].block.setName("grass"); + binded[2].block.setName("water"); + binded[3].block.setName("wood"); + binded[4].block.setName("asphalt"); + binded[5].block.setName("torch"); + binded[8].block.setName("grass"); + binded[9].block.setName("dirt"); + frame = new Frame(0, 0, 0, BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE); + select(0); + } + + public void onKeyDown() { + // System.out.println("keyName: " + api.keyboard.keyName); + int key = Keyboard.getEventKey(); + if (key == Keyboard.KEY_1) { + select(0); + } + if (key == Keyboard.KEY_2) { + select(1); + } + if (key == Keyboard.KEY_3) { + select(2); + } + if (key == Keyboard.KEY_4) { + select(3); + } + if (key == Keyboard.KEY_5) { + select(4); + } + if (key == Keyboard.KEY_6) { + select(5); + } + if (key == Keyboard.KEY_7) { + select(6); + } + if (key == Keyboard.KEY_8) { + select(7); + } + if (key == Keyboard.KEY_9) { + select(8); + } + if (key == Keyboard.KEY_0) { + select(9); + } + if (key == Keyboard.KEY_E) { + isInventoryGUIOpen = !isInventoryGUIOpen; + } + + } + + public void select(int i) { + selected = binded[i]; + } +} diff --git a/src/ru/olamedia/olacraft/inventory/package-info.java b/src/ru/olamedia/olacraft/inventory/package-info.java new file mode 100644 index 0000000..fe2b1fc --- /dev/null +++ b/src/ru/olamedia/olacraft/inventory/package-info.java @@ -0,0 +1,9 @@ +/** + * + */ +/** + * @author olamedia + * + */ +package ru.olamedia.olacraft.inventory; + diff --git a/src/ru/olamedia/olacraft/network/ConnectionState.java b/src/ru/olamedia/olacraft/network/ConnectionState.java new file mode 100644 index 0000000..2d6c5c5 --- /dev/null +++ b/src/ru/olamedia/olacraft/network/ConnectionState.java @@ -0,0 +1,17 @@ +package ru.olamedia.olacraft.network; + +public class ConnectionState { + private int state; + + public ConnectionState(int state) { + this.state = state; + } + + public static ConnectionState STATE_DISCONNECTED = new ConnectionState(0); + public static ConnectionState STATE_CONNECTED = new ConnectionState(1); + public static ConnectionState STATE_CONNECTING = new ConnectionState(2); + + public boolean isConnected() { + return state == 1; + } +} diff --git a/src/ru/olamedia/olacraft/network/ConnectionStateListener.java b/src/ru/olamedia/olacraft/network/ConnectionStateListener.java new file mode 100644 index 0000000..6220029 --- /dev/null +++ b/src/ru/olamedia/olacraft/network/ConnectionStateListener.java @@ -0,0 +1,7 @@ +package ru.olamedia.olacraft.network; + +public class ConnectionStateListener { + public void onChangeState(ConnectionState state){ + // override + } +} diff --git a/src/ru/olamedia/olacraft/network/GameClient.java b/src/ru/olamedia/olacraft/network/GameClient.java new file mode 100644 index 0000000..669d954 --- /dev/null +++ b/src/ru/olamedia/olacraft/network/GameClient.java @@ -0,0 +1,209 @@ +package ru.olamedia.olacraft.network; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +import com.esotericsoftware.kryo.Kryo; +import com.esotericsoftware.kryonet.Client; +import com.esotericsoftware.kryonet.Connection; +import com.esotericsoftware.kryonet.Listener; + +import ru.olamedia.game.GameManager; +import ru.olamedia.liveEntity.LiveEntity; +import ru.olamedia.olacraft.game.Game; +import ru.olamedia.olacraft.network.packet.ConnectionPacket; +import ru.olamedia.olacraft.network.packet.ConnectionRequestPacket; +import ru.olamedia.olacraft.network.packet.IPacket; +import ru.olamedia.olacraft.network.packet.IPacketListener; +import ru.olamedia.olacraft.network.packet.LiveEntityLocationUpdatePacket; +import ru.olamedia.olacraft.network.packet.SpawnPacket; +import ru.olamedia.olacraft.network.packet.SpawnRequestPacket; +import ru.olamedia.olacraft.network.packet.WorldInfoPacket; +import ru.olamedia.olacraft.scene.GameScene; +import ru.olamedia.olacraft.world.WorldInfo; +import ru.olamedia.olacraft.world.dataProvider.CachedChunkDataProvider; +import ru.olamedia.olacraft.world.dataProvider.RemoteChunkDataProvider; +import ru.olamedia.olacraft.world.provider.WorldProvider; + +public class GameClient extends ConnectionStateListener implements IPacketListener { + private WorldProvider worldProvider; + private GameScene scene; + + private Client client = new Client(70 * 1024 * 1024, 70 * 1024 * 1024); + private String hostname = "127.0.0.1"; + + @Override + public void onChangeState(ConnectionState state) { + if (state.isConnected()) { + GameManager.instance.hideMainMenu(); + client.sendTCP(new ConnectionRequestPacket()); + // + // provider.load(0, 0, 0); + // provider.load(1, 2, 3); + } + } + + /* + * public AbstractChunkDataProvider getChunkDataProvider() { + * return worldProvider.getChunkDataProvider(); + * } + */ + + public WorldProvider getWorldProvider() { + return worldProvider; + } + + private List<ConnectionStateListener> stateListeners = new ArrayList<ConnectionStateListener>(); + private List<IPacketListener> packetListeners = new ArrayList<IPacketListener>(); + private ExecutorService threadPool = Executors.newFixedThreadPool(1); + + public GameClient() { + // INIT WORLD + worldProvider = new WorldProvider(); + worldProvider.setChunkDataProvider(new CachedChunkDataProvider(new RemoteChunkDataProvider(this))); + // CREATE SCENE + scene = new GameScene(worldProvider); + Kryo kryo = client.getKryo(); + Network.registerPackets(kryo); + addStateListener(this); + addPacketListener(this); + client.addListener(new Listener.ThreadedListener(new Listener() { + + @Override + public void received(Connection connection, Object object) { + if (object instanceof IPacket) { + dispatchPacket(connection, (IPacket) object); + } + } + + @Override + public void disconnected(Connection connection) { + super.disconnected(connection); + dispatchState(ConnectionState.STATE_DISCONNECTED); + } + }, threadPool)); + client.start(); + } + + public void addStateListener(ConnectionStateListener listener) { + stateListeners.add(listener); + } + + private void dispatchState(ConnectionState state) { + for (ConnectionStateListener l : stateListeners) { + l.onChangeState(state); + } + } + + private void dispatchPacket(Connection connection, IPacket p) { + for (IPacketListener l : packetListeners) { + l.onPacket(connection, p); + } + } + + public void connect() { + new Thread("Connect") { + public void run() { + try { + dispatchState(ConnectionState.STATE_CONNECTING); + client.connect(5000, hostname, Game.port); + dispatchState(ConnectionState.STATE_CONNECTED); + } catch (IOException ex) { + dispatchState(ConnectionState.STATE_DISCONNECTED); + } + } + }.start(); + } + + public void close() { + client.close(); + } + + public void send(IPacket p) { + client.sendTCP(p); + } + + public void addPacketListener(IPacketListener listener) { + packetListeners.add(listener); + } + + public boolean isConnected() { + return client.isConnected(); + } + + private static boolean DEBUG = true; + + private void debug(String s) { + if (DEBUG) { + System.out.println("[GameClient] " + s); + } + } + + @Override + public void onPacket(Connection connection, IPacket p) { + debug("received " + p.getClass().getName()); + // 1. receive ConnectionPacket, send SpawnRequestPacket + if (p instanceof ConnectionPacket) { + Game.instance.player.setConnectionId(((ConnectionPacket) p).connectionId); + send(new SpawnRequestPacket()); + } + if (p instanceof WorldInfoPacket) { + worldProvider.setInfo(((WorldInfoPacket) p).info); + } + // 2. Receive SpawnPacket + if (p instanceof SpawnPacket) { + LiveEntity entity; + if (((SpawnPacket) p).connectionId == client.getID()) { + // me + entity = Game.instance.player; + } else { + // another player + entity = new LiveEntity(); + } + entity.setX(((SpawnPacket) p).x); + entity.setY(((SpawnPacket) p).y); + entity.setZ(((SpawnPacket) p).z); + entity.setConnectionId(((SpawnPacket) p).connectionId); + scene.registerLiveEntity(entity); + if (((SpawnPacket) p).connectionId == client.getID()) { + // me + scene.registerPlayer(entity); + } + } + if (p instanceof LiveEntityLocationUpdatePacket) { + LiveEntity entity = scene.getLiveEntity(((LiveEntityLocationUpdatePacket) p).connectionId); + if (null != entity) { + entity.setX(((LiveEntityLocationUpdatePacket) p).x); + entity.setY(((LiveEntityLocationUpdatePacket) p).y); + entity.setZ(((LiveEntityLocationUpdatePacket) p).z); + } + } + } + + public String getHostname() { + return hostname; + } + + public void setHostname(String hostname) { + this.hostname = hostname; + } + + public void dispose() { + client.close(); + client.stop(); + // threadPool.awaitTermination(1000, TimeUnit.MILLISECONDS); + threadPool.shutdownNow(); + } + + public GameScene getScene() { + return scene; + } + + public WorldInfo getWorldInfo() { + return worldProvider.getInfo(); + } + +} diff --git a/src/ru/olamedia/olacraft/network/GameServer.java b/src/ru/olamedia/olacraft/network/GameServer.java new file mode 100644 index 0000000..67dffc5 --- /dev/null +++ b/src/ru/olamedia/olacraft/network/GameServer.java @@ -0,0 +1,169 @@ +package ru.olamedia.olacraft.network; + +import java.io.IOException; +import java.net.BindException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +import ru.olamedia.liveEntity.LiveEntity; +import ru.olamedia.olacraft.game.Game; +import ru.olamedia.olacraft.game.SpawnLocation; +import ru.olamedia.olacraft.network.discovery.DiscoveryThread; +import ru.olamedia.olacraft.network.packet.ConnectionPacket; +import ru.olamedia.olacraft.network.packet.ConnectionRequestPacket; +import ru.olamedia.olacraft.network.packet.GetRegionPacket; +import ru.olamedia.olacraft.network.packet.IPacket; +import ru.olamedia.olacraft.network.packet.LiveEntityLocationUpdatePacket; +import ru.olamedia.olacraft.network.packet.RegionDataPacket; +import ru.olamedia.olacraft.network.packet.SpawnPacket; +import ru.olamedia.olacraft.network.packet.SpawnRequestPacket; +import ru.olamedia.olacraft.network.packet.WorldInfoPacket; +import ru.olamedia.olacraft.scene.GameScene; +import ru.olamedia.olacraft.world.data.RegionData; +import ru.olamedia.olacraft.world.dataProvider.CachedChunkDataProvider; +import ru.olamedia.olacraft.world.dataProvider.LocalChunkDataProvider; +import ru.olamedia.olacraft.world.provider.WorldProvider; + +import com.esotericsoftware.kryo.Kryo; +import com.esotericsoftware.kryonet.Connection; +import com.esotericsoftware.kryonet.Listener; +import com.esotericsoftware.kryonet.Server; + +public class GameServer { + private WorldProvider worldProvider; + + private ExecutorService threadPool = Executors.newFixedThreadPool(1); + public static Server server = new Server(70 * 1024 * 1024, 1024 * 1024) { + @Override + protected PlayerConnection newConnection() { + // By providing our own connection implementation, we can store per + // connection state without a connection ID to state look up. + return new PlayerConnection(); + } + }; + private boolean isServerRunning = false; + + private GameScene scene; + + private static boolean DEBUG = true; + + private void debug(String s) { + if (DEBUG) { + System.out.println("[GameServer] " + s); + } + } + + public GameServer() { + // INIT WORLD + worldProvider = new WorldProvider(); + worldProvider.setChunkDataProvider(new CachedChunkDataProvider(new LocalChunkDataProvider(worldProvider.getInfo().name))); + // CREATE SCENE + scene = new GameScene(worldProvider); + // worldProvider.getInfo().name = "world"; + Kryo kryo = server.getKryo(); + Network.registerPackets(kryo); + server.addListener(new Listener.ThreadedListener(new Listener() { + @Override + public void disconnected(Connection connection) { + } + + @Override + public void received(Connection connection, Object object) { + debug("received " + object.getClass()); + if (object instanceof ConnectionRequestPacket) { + ConnectionPacket p = new ConnectionPacket(); + p.connectionId = connection.getID(); + server.sendToTCP(connection.getID(), p); + } + if (object instanceof GetRegionPacket) { + GetRegionPacket p = (GetRegionPacket) object; + RegionData data = worldProvider.getRegion(p.location); + RegionDataPacket response = new RegionDataPacket(); + response.data = data; + server.sendToTCP(connection.getID(), response); + } + if (object instanceof SpawnRequestPacket) { + SpawnLocation loc = worldProvider.getSpawnLocation(connection.getID()); + if (null != loc) { + server.sendToTCP(connection.getID(), new WorldInfoPacket(worldProvider)); + LiveEntity entity = new LiveEntity(); + entity.setX(loc.x); + entity.setY(loc.y); + entity.setZ(loc.z); + entity.setConnectionId(connection.getID()); + scene.registerLiveEntity(entity); + // send all entity locations + for (LiveEntity nextEntity : scene.getLiveEntities().values()) { + SpawnPacket p = new SpawnPacket(); + p.x = nextEntity.getX(); + p.y = nextEntity.getY(); + p.z = nextEntity.getZ(); + p.connectionId = nextEntity.getConnectionId(); + if (p.connectionId == connection.getID()) { + server.sendToAllTCP(p); + } else { + server.sendToTCP(connection.getID(), p); + } + } + } + } + if (object instanceof LiveEntityLocationUpdatePacket) { + LiveEntityLocationUpdatePacket p = ((LiveEntityLocationUpdatePacket) object); + p.connectionId = connection.getID(); + LiveEntity entity = scene.getLiveEntity(connection.getID()); + if (null != entity) { + entity.setLocation(p.x, p.y, p.z); + server.sendToAllTCP(object); + } + } + + // super.received(connection, object); + } + }, threadPool)); + } + + private DiscoveryThread discovery; + + public void start() { + try { + server.start(); + server.bind(Game.port); + discovery = new DiscoveryThread("SERVER DISCOVERY"); + discovery.start(); + isServerRunning = true; + // server.addListener(new Listener()); + } catch (BindException ex) { + server.stop(); + if (null != discovery && discovery.isAlive()) { + discovery.interrupt(); + } + isServerRunning = false; + } catch (IOException e1) { + server.stop(); + if (null != discovery && discovery.isAlive()) { + discovery.interrupt(); + } + e1.printStackTrace(); + isServerRunning = false; + } + } + + public void stop() { + server.close(); + server.stop(); + isServerRunning = false; + } + + public boolean isRunning() { + return isServerRunning; + } + + public void send(IPacket p) { + } + + public void dispose() { + stop(); + // threadPool.awaitTermination(1000, TimeUnit.MILLISECONDS); + threadPool.shutdownNow(); + } +} diff --git a/src/ru/olamedia/olacraft/network/Network.java b/src/ru/olamedia/olacraft/network/Network.java new file mode 100644 index 0000000..2ba8eab --- /dev/null +++ b/src/ru/olamedia/olacraft/network/Network.java @@ -0,0 +1,71 @@ +package ru.olamedia.olacraft.network; + +import java.util.BitSet; + +import ru.olamedia.olacraft.network.packet.ChunkDataPacket; +import ru.olamedia.olacraft.network.packet.ConnectionPacket; +import ru.olamedia.olacraft.network.packet.ConnectionRequestPacket; +import ru.olamedia.olacraft.network.packet.GetChunkDataPacket; +import ru.olamedia.olacraft.network.packet.GetRegionPacket; +import ru.olamedia.olacraft.network.packet.LiveEntityLocationUpdatePacket; +import ru.olamedia.olacraft.network.packet.RegionDataPacket; +import ru.olamedia.olacraft.network.packet.SpawnPacket; +import ru.olamedia.olacraft.network.packet.SpawnRequestPacket; +import ru.olamedia.olacraft.network.packet.WorldInfoPacket; +import ru.olamedia.olacraft.world.WorldInfo; +import ru.olamedia.olacraft.world.data.ChunkData; +import ru.olamedia.olacraft.world.data.ChunkLightData; +import ru.olamedia.olacraft.world.data.HeightMap; +import ru.olamedia.olacraft.world.data.RegionData; +import ru.olamedia.olacraft.world.data.SectorData; +import ru.olamedia.olacraft.world.location.BlockLocation; +import ru.olamedia.olacraft.world.location.ChunkLocation; +import ru.olamedia.olacraft.world.location.RegionLocation; +import ru.olamedia.olacraft.world.location.SectorLocation; + +import com.esotericsoftware.kryo.Kryo; + +public class Network { + public static void registerPackets(Kryo kryo) { + // types + kryo.register(boolean.class); + kryo.register(boolean[].class); + kryo.register(byte.class); + kryo.register(byte[].class); + kryo.register(byte[][].class); + kryo.register(int.class); + kryo.register(int[].class); + kryo.register(float.class); + kryo.register(float[].class); + kryo.register(long.class); + kryo.register(long[].class); + kryo.register(BitSet.class); + kryo.register(HeightMap.class); + kryo.register(WorldInfo.class); + kryo.register(WorldInfoPacket.class); + kryo.register(BlockLocation.class); + kryo.register(ChunkLocation.class); + kryo.register(SectorLocation.class); + kryo.register(RegionLocation.class); + kryo.register(ChunkData.class); + kryo.register(ChunkData[].class); + kryo.register(SectorData.class); + kryo.register(SectorData[].class); + kryo.register(SectorData[][].class); + kryo.register(RegionData.class); + kryo.register(GetRegionPacket.class); + kryo.register(RegionDataPacket.class); + + + kryo.register(ChunkLightData.class); + kryo.register(ChunkData.class); + // packets + kryo.register(ConnectionRequestPacket.class); + kryo.register(ConnectionPacket.class); + kryo.register(SpawnRequestPacket.class); + kryo.register(SpawnPacket.class); + kryo.register(GetChunkDataPacket.class); + kryo.register(ChunkDataPacket.class); + kryo.register(LiveEntityLocationUpdatePacket.class); + } +} diff --git a/src/ru/olamedia/olacraft/network/PlayerConnection.java b/src/ru/olamedia/olacraft/network/PlayerConnection.java new file mode 100644 index 0000000..3120b4d --- /dev/null +++ b/src/ru/olamedia/olacraft/network/PlayerConnection.java @@ -0,0 +1,9 @@ +package ru.olamedia.olacraft.network; + +import ru.olamedia.liveEntity.LiveEntity; + +import com.esotericsoftware.kryonet.Connection; + +public class PlayerConnection extends Connection{ + public LiveEntity entity; +} diff --git a/src/ru/olamedia/olacraft/network/discovery/DiscoveryClient.java b/src/ru/olamedia/olacraft/network/discovery/DiscoveryClient.java new file mode 100644 index 0000000..629e6e3 --- /dev/null +++ b/src/ru/olamedia/olacraft/network/discovery/DiscoveryClient.java @@ -0,0 +1,143 @@ +package ru.olamedia.olacraft.network.discovery; + +import java.io.IOException; +import java.net.DatagramPacket; +import java.net.DatagramSocket; +import java.net.InetAddress; +import java.net.InterfaceAddress; +import java.net.NetworkInterface; +import java.net.SocketTimeoutException; +import java.net.UnknownHostException; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.List; + +import ru.olamedia.tasks.Task; + +public class DiscoveryClient extends Task { + private static DatagramSocket c; + public static List<InetAddress> list = new ArrayList<InetAddress>(); + private static List<DiscoveryListener> listeners = new ArrayList<DiscoveryListener>(); + + public void addHostListener(DiscoveryListener listener) { + listeners.add(listener); + } + + public static void discovery() { + list.clear(); + try { + list.add(InetAddress.getByName("127.0.0.1")); + } catch (UnknownHostException e1) { + e1.printStackTrace(); + } + // Find the server using UDP broadcast + try { + // Open a random port to send the package + c = new DatagramSocket(); + c.setBroadcast(true); + c.setSoTimeout(3000); + + byte[] sendData = "DISCOVER_OLACRAFTSERVER_REQUEST".getBytes(); + + // Try the 255.255.255.255 first + try { + DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, + InetAddress.getByName("255.255.255.255"), DiscoveryThread.port); + c.send(sendPacket); + System.out.println(DiscoveryClient.class.getName() + + ">>> Request packet sent to: 255.255.255.255 (DEFAULT)"); + } catch (Exception e) { + } + + // Broadcast the message over all the network interfaces + @SuppressWarnings("rawtypes") + Enumeration interfaces = NetworkInterface.getNetworkInterfaces(); + while (interfaces.hasMoreElements()) { + NetworkInterface networkInterface = (NetworkInterface) interfaces.nextElement(); + + if (networkInterface.isLoopback() || !networkInterface.isUp()) { + continue; // Don't want to broadcast to the loopback + // interface + } + + for (InterfaceAddress interfaceAddress : networkInterface.getInterfaceAddresses()) { + InetAddress broadcast = interfaceAddress.getBroadcast(); + if (broadcast == null) { + continue; + } + + // Send the broadcast package! + try { + DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, broadcast, 8888); + c.send(sendPacket); + } catch (Exception e) { + } + + System.out.println(DiscoveryClient.class.getName() + ">>> Request packet sent to: " + + broadcast.getHostAddress() + "; Interface: " + networkInterface.getDisplayName()); + } + } + + System.out.println(DiscoveryClient.class.getName() + + ">>> Done looping over all network interfaces. Now waiting for a reply!"); + while (true) { + // Wait for a response + byte[] recvBuf = new byte[15000]; + DatagramPacket receivePacket = new DatagramPacket(recvBuf, recvBuf.length); + c.receive(receivePacket); + + // We have a response + System.out.println(DiscoveryClient.class.getName() + ">>> Broadcast response from server: " + + receivePacket.getAddress().getHostAddress()); + + // Check if the message is correct + String message = new String(receivePacket.getData()).trim(); + if (message.equals("DISCOVER_OLACRAFTSERVER_RESPONSE")) { + list.add(receivePacket.getAddress()); + for (DiscoveryListener l : listeners) { + l.onHost(receivePacket.getAddress()); + } + // DO SOMETHING WITH THE SERVER'S IP (for example, store it + // in + // your controller) + // Controller_Base.setServerIp(receivePacket.getAddress()); + } + } + } catch (SocketTimeoutException ex) { + // no hosts were discovered + } catch (IOException ex) { + // no hosts were discovered + } finally { + // Close the port! + if (null != c) { + c.close(); + } + for (DiscoveryListener l : listeners) { + l.onHost(null); // end of list marker + } + } + } + + @Override + public void run() { +// while (!shouldStop()) { + discovery(); + // try { + // wait(3000); + // } catch (InterruptedException e) { + // e.printStackTrace(); + // } + // } + } + + public void refresh() { + } + + public static DiscoveryClient getInstance() { + return DiscoveryThreadHolder.INSTANCE; + } + + private static class DiscoveryThreadHolder { + private static final DiscoveryClient INSTANCE = new DiscoveryClient(); + } +} diff --git a/src/ru/olamedia/olacraft/network/discovery/DiscoveryListener.java b/src/ru/olamedia/olacraft/network/discovery/DiscoveryListener.java new file mode 100644 index 0000000..81c1019 --- /dev/null +++ b/src/ru/olamedia/olacraft/network/discovery/DiscoveryListener.java @@ -0,0 +1,9 @@ +package ru.olamedia.olacraft.network.discovery; + +import java.net.InetAddress; + +public class DiscoveryListener { + public void onHost(InetAddress address){ + + } +} diff --git a/src/ru/olamedia/olacraft/network/discovery/DiscoveryThread.java b/src/ru/olamedia/olacraft/network/discovery/DiscoveryThread.java new file mode 100644 index 0000000..a6302fa --- /dev/null +++ b/src/ru/olamedia/olacraft/network/discovery/DiscoveryThread.java @@ -0,0 +1,91 @@ +package ru.olamedia.olacraft.network.discovery; + +import java.io.IOException; +import java.net.DatagramPacket; +import java.net.DatagramSocket; +import java.net.InetAddress; +import java.net.SocketException; +import java.net.SocketTimeoutException; +import java.net.UnknownHostException; + +public class DiscoveryThread extends Thread { + public DiscoveryThread() { + super(); + try { + socket = new DatagramSocket(port, InetAddress.getByName("0.0.0.0")); + socket.setBroadcast(true); + socket.setSoTimeout(1000); + } catch (SocketException e) { + e.printStackTrace(); + } catch (UnknownHostException e) { + e.printStackTrace(); + } + } + + public DiscoveryThread(String name) { + this(); + setName(name); + } + + private DatagramSocket socket; + public static int port = 26003; + + @Override + public void run() { + try { + System.out.println(getClass().getName() + ">>>Ready to receive broadcast packets!"); + while (true) { + + // Receive a packet + byte[] recvBuf = new byte[15000]; + DatagramPacket packet = new DatagramPacket(recvBuf, recvBuf.length); + try { + socket.receive(packet); + + // Packet received + System.out.println(getClass().getName() + ">>>Discovery packet received from: " + + packet.getAddress().getHostAddress()); + System.out.println(getClass().getName() + ">>>Packet received; data: " + + new String(packet.getData())); + + // See if the packet holds the right command (message) + String message = new String(packet.getData()).trim(); + if (message.equals("DISCOVER_OLACRAFTSERVER_REQUEST")) { + byte[] sendData = "DISCOVER_OLACRAFTSERVER_RESPONSE".getBytes(); + + // Send a response + DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, packet.getAddress(), + packet.getPort()); + socket.send(sendPacket); + + System.out.println(getClass().getName() + ">>>Sent packet to: " + + sendPacket.getAddress().getHostAddress()); + } + } catch (SocketTimeoutException ex) { + + } + try { + Thread.sleep(100); + } catch (IllegalMonitorStateException ex) { + ex.printStackTrace(); + } catch (InterruptedException ex) { + socket.close(); + Thread.currentThread().interrupt(); // very important + break; + } + } + } catch (IOException ex) { + socket.close(); + } + } + + public static DiscoveryThread getInstance() { + return DiscoveryThreadHolder.INSTANCE; + } + + private static class DiscoveryThreadHolder { + + private static final DiscoveryThread INSTANCE = new DiscoveryThread(); + } + +} diff --git a/src/ru/olamedia/olacraft/network/discovery/package-info.java b/src/ru/olamedia/olacraft/network/discovery/package-info.java new file mode 100644 index 0000000..cb376c8 --- /dev/null +++ b/src/ru/olamedia/olacraft/network/discovery/package-info.java @@ -0,0 +1,8 @@ +/** + * + */ +/** + * @author olamedia + * + */ +package ru.olamedia.olacraft.network.discovery;
\ No newline at end of file diff --git a/src/ru/olamedia/olacraft/network/package-info.java b/src/ru/olamedia/olacraft/network/package-info.java new file mode 100644 index 0000000..dfbaec9 --- /dev/null +++ b/src/ru/olamedia/olacraft/network/package-info.java @@ -0,0 +1,9 @@ +/** + * + */ +/** + * Used KryoNet library (Which is under BSD License) + * @author olamedia + * + */ +package ru.olamedia.olacraft.network;
\ No newline at end of file diff --git a/src/ru/olamedia/olacraft/network/packet/ChatMessagePacket.java b/src/ru/olamedia/olacraft/network/packet/ChatMessagePacket.java new file mode 100644 index 0000000..332c9dd --- /dev/null +++ b/src/ru/olamedia/olacraft/network/packet/ChatMessagePacket.java @@ -0,0 +1,5 @@ +package ru.olamedia.olacraft.network.packet; + +public class ChatMessagePacket implements IPacket { + public String message; +} diff --git a/src/ru/olamedia/olacraft/network/packet/ChunkDataPacket.java b/src/ru/olamedia/olacraft/network/packet/ChunkDataPacket.java new file mode 100644 index 0000000..1bf92c4 --- /dev/null +++ b/src/ru/olamedia/olacraft/network/packet/ChunkDataPacket.java @@ -0,0 +1,10 @@ +package ru.olamedia.olacraft.network.packet; + +import ru.olamedia.olacraft.world.data.ChunkData; + +public class ChunkDataPacket implements IPacket { + public int chunkX; + public int chunkY; + public int chunkZ; + public ChunkData data; +} diff --git a/src/ru/olamedia/olacraft/network/packet/ConnectionPacket.java b/src/ru/olamedia/olacraft/network/packet/ConnectionPacket.java new file mode 100644 index 0000000..ced43d5 --- /dev/null +++ b/src/ru/olamedia/olacraft/network/packet/ConnectionPacket.java @@ -0,0 +1,11 @@ +package ru.olamedia.olacraft.network.packet; + +/** + * Server sends connection packet with assigned connection ID on client connect + * + * @author olamedia + * + */ +public class ConnectionPacket implements IPacket{ + public int connectionId; +} diff --git a/src/ru/olamedia/olacraft/network/packet/ConnectionRequestPacket.java b/src/ru/olamedia/olacraft/network/packet/ConnectionRequestPacket.java new file mode 100644 index 0000000..419f339 --- /dev/null +++ b/src/ru/olamedia/olacraft/network/packet/ConnectionRequestPacket.java @@ -0,0 +1,5 @@ +package ru.olamedia.olacraft.network.packet; + +public class ConnectionRequestPacket implements IPacket{ + +} diff --git a/src/ru/olamedia/olacraft/network/packet/GetChunkDataPacket.java b/src/ru/olamedia/olacraft/network/packet/GetChunkDataPacket.java new file mode 100644 index 0000000..492ce15 --- /dev/null +++ b/src/ru/olamedia/olacraft/network/packet/GetChunkDataPacket.java @@ -0,0 +1,7 @@ +package ru.olamedia.olacraft.network.packet; + +public class GetChunkDataPacket implements IPacket{ + public int chunkX; + public int chunkY; + public int chunkZ; +} diff --git a/src/ru/olamedia/olacraft/network/packet/GetRegionPacket.java b/src/ru/olamedia/olacraft/network/packet/GetRegionPacket.java new file mode 100644 index 0000000..2c57057 --- /dev/null +++ b/src/ru/olamedia/olacraft/network/packet/GetRegionPacket.java @@ -0,0 +1,15 @@ +package ru.olamedia.olacraft.network.packet; + +import ru.olamedia.olacraft.world.location.RegionLocation; + +public class GetRegionPacket implements IPacket { + public RegionLocation location; + + public GetRegionPacket() { + + } + + public GetRegionPacket(RegionLocation location) { + this.location = location; + } +} diff --git a/src/ru/olamedia/olacraft/network/packet/IPacket.java b/src/ru/olamedia/olacraft/network/packet/IPacket.java new file mode 100644 index 0000000..adfa3c7 --- /dev/null +++ b/src/ru/olamedia/olacraft/network/packet/IPacket.java @@ -0,0 +1,5 @@ +package ru.olamedia.olacraft.network.packet; + +public interface IPacket { + +} diff --git a/src/ru/olamedia/olacraft/network/packet/IPacketListener.java b/src/ru/olamedia/olacraft/network/packet/IPacketListener.java new file mode 100644 index 0000000..2a17cd4 --- /dev/null +++ b/src/ru/olamedia/olacraft/network/packet/IPacketListener.java @@ -0,0 +1,7 @@ +package ru.olamedia.olacraft.network.packet; + +import com.esotericsoftware.kryonet.Connection; + +public interface IPacketListener { + public void onPacket(Connection connection, IPacket p); +} diff --git a/src/ru/olamedia/olacraft/network/packet/LiveEntityLocationUpdatePacket.java b/src/ru/olamedia/olacraft/network/packet/LiveEntityLocationUpdatePacket.java new file mode 100644 index 0000000..15edfd9 --- /dev/null +++ b/src/ru/olamedia/olacraft/network/packet/LiveEntityLocationUpdatePacket.java @@ -0,0 +1,15 @@ +package ru.olamedia.olacraft.network.packet; + +/** + * Client sends this packet every time location changed + * Server fills connectionId and sends back to every connection + * + * @author olamedia + * + */ +public class LiveEntityLocationUpdatePacket implements IPacket { + public float x; + public float y; + public float z; + public int connectionId; // filled by server only +} diff --git a/src/ru/olamedia/olacraft/network/packet/RegionDataPacket.java b/src/ru/olamedia/olacraft/network/packet/RegionDataPacket.java new file mode 100644 index 0000000..3a60230 --- /dev/null +++ b/src/ru/olamedia/olacraft/network/packet/RegionDataPacket.java @@ -0,0 +1,7 @@ +package ru.olamedia.olacraft.network.packet; + +import ru.olamedia.olacraft.world.data.RegionData; + +public class RegionDataPacket implements IPacket { + public RegionData data; +} diff --git a/src/ru/olamedia/olacraft/network/packet/SpawnPacket.java b/src/ru/olamedia/olacraft/network/packet/SpawnPacket.java new file mode 100644 index 0000000..d25a692 --- /dev/null +++ b/src/ru/olamedia/olacraft/network/packet/SpawnPacket.java @@ -0,0 +1,15 @@ +package ru.olamedia.olacraft.network.packet; + +/** + * Client sends SpawnRequestPacket on connect + * Server fills location, connectionId and sends SpawnPacket to every connection + * + * @author olamedia + * + */ +public class SpawnPacket implements IPacket { + public float x; + public float y; + public float z; + public int connectionId; // filled by server only +} diff --git a/src/ru/olamedia/olacraft/network/packet/SpawnRequestPacket.java b/src/ru/olamedia/olacraft/network/packet/SpawnRequestPacket.java new file mode 100644 index 0000000..0628272 --- /dev/null +++ b/src/ru/olamedia/olacraft/network/packet/SpawnRequestPacket.java @@ -0,0 +1,4 @@ +package ru.olamedia.olacraft.network.packet; + +public class SpawnRequestPacket implements IPacket { +} diff --git a/src/ru/olamedia/olacraft/network/packet/WorldInfoPacket.java b/src/ru/olamedia/olacraft/network/packet/WorldInfoPacket.java new file mode 100644 index 0000000..9c8e1c7 --- /dev/null +++ b/src/ru/olamedia/olacraft/network/packet/WorldInfoPacket.java @@ -0,0 +1,15 @@ +package ru.olamedia.olacraft.network.packet; + +import ru.olamedia.olacraft.world.WorldInfo; +import ru.olamedia.olacraft.world.provider.WorldProvider; + +public class WorldInfoPacket implements IPacket { + public WorldInfoPacket(){ + + } + public WorldInfoPacket(WorldProvider worldProvider) { + info = worldProvider.getInfo(); + } + + public WorldInfo info; +} diff --git a/src/ru/olamedia/olacraft/network/packet/package-info.java b/src/ru/olamedia/olacraft/network/packet/package-info.java new file mode 100644 index 0000000..a1da5fd --- /dev/null +++ b/src/ru/olamedia/olacraft/network/packet/package-info.java @@ -0,0 +1,8 @@ +/** + * + */ +/** + * @author olamedia + * + */ +package ru.olamedia.olacraft.network.packet;
\ No newline at end of file diff --git a/src/ru/olamedia/olacraft/package-info.java b/src/ru/olamedia/olacraft/package-info.java new file mode 100644 index 0000000..0049efb --- /dev/null +++ b/src/ru/olamedia/olacraft/package-info.java @@ -0,0 +1,8 @@ +/** + * + */ +/** + * @author olamedia + * + */ +package ru.olamedia.olacraft; diff --git a/src/ru/olamedia/olacraft/physics/GamePhysicsWorld.java b/src/ru/olamedia/olacraft/physics/GamePhysicsWorld.java new file mode 100644 index 0000000..dd66ef0 --- /dev/null +++ b/src/ru/olamedia/olacraft/physics/GamePhysicsWorld.java @@ -0,0 +1,27 @@ +package ru.olamedia.olacraft.physics; + +import org.ode4j.ode.DBody; +import org.ode4j.ode.DRay; +import org.ode4j.ode.DWorld; +import org.ode4j.ode.OdeHelper; + +public class GamePhysicsWorld { + private DWorld world; + + public GamePhysicsWorld() { + world = OdeHelper.createWorld(); + world.setGravity(0, -0.98, 0); + } + + public DWorld getWorld() { + return world; + } + + public DBody createBody(){ + return OdeHelper.createBody(world); + } + + public DRay createRay(int length){ + return OdeHelper.createRay(length); + } +} diff --git a/src/ru/olamedia/olacraft/physics/package-info.java b/src/ru/olamedia/olacraft/physics/package-info.java new file mode 100644 index 0000000..6eaba10 --- /dev/null +++ b/src/ru/olamedia/olacraft/physics/package-info.java @@ -0,0 +1,8 @@ +/** + * + */ +/** + * @author olamedia + * + */ +package ru.olamedia.olacraft.physics;
\ No newline at end of file diff --git a/src/ru/olamedia/olacraft/picker/joglBlockPicker.java b/src/ru/olamedia/olacraft/picker/joglBlockPicker.java new file mode 100644 index 0000000..6eb279c --- /dev/null +++ b/src/ru/olamedia/olacraft/picker/joglBlockPicker.java @@ -0,0 +1,27 @@ +package ru.olamedia.olacraft.picker; + +import java.nio.FloatBuffer; + +import javax.media.opengl.GL2; +import javax.media.opengl.GLAutoDrawable; + +import ru.olamedia.olacraft.world.block.Block; +import ru.olamedia.olacraft.world.provider.ChunkProvider; + +public class joglBlockPicker { + ChunkProvider provider; + + public void setChunkProvider(ChunkProvider provider) { + this.provider = provider; + } + + public Block pickBlock(GLAutoDrawable drawable) { + GL2 gl = drawable.getGL().getGL2(); + FloatBuffer projMatrix = FloatBuffer.allocate(16); + FloatBuffer modelMatrix = FloatBuffer.allocate(16); + gl.glGetFloatv(GL2.GL_PROJECTION, projMatrix); + gl.glGetFloatv(GL2.GL_MODELVIEW, modelMatrix); + + return null; + } +} diff --git a/src/ru/olamedia/olacraft/picker/package-info.java b/src/ru/olamedia/olacraft/picker/package-info.java new file mode 100644 index 0000000..b254232 --- /dev/null +++ b/src/ru/olamedia/olacraft/picker/package-info.java @@ -0,0 +1,8 @@ +/** + * + */ +/** + * @author olamedia + * + */ +package ru.olamedia.olacraft.picker;
\ No newline at end of file diff --git a/src/ru/olamedia/olacraft/render/jogl/BlockRenderer.java b/src/ru/olamedia/olacraft/render/jogl/BlockRenderer.java new file mode 100644 index 0000000..6d96403 --- /dev/null +++ b/src/ru/olamedia/olacraft/render/jogl/BlockRenderer.java @@ -0,0 +1,87 @@ +package ru.olamedia.olacraft.render.jogl; + +import javax.media.opengl.GL; +import javax.media.opengl.GL2; +import javax.media.opengl.GLAutoDrawable; + +import com.jogamp.opengl.util.texture.Texture; +import com.jogamp.opengl.util.texture.TextureCoords; + +import ru.olamedia.geom.SimpleQuadMesh; +import ru.olamedia.olacraft.world.chunk.BlockSlice; +import ru.olamedia.texture.TextureManager; + +public class BlockRenderer { + private BlockSlice slice; + private SimpleQuadMesh mesh; + + public BlockRenderer(BlockSlice slice) { + this.slice = slice; + } + + public SimpleQuadMesh getMesh(GL glx) { + GL2 gl = glx.getGL2(); + // 14739 + SimpleQuadMesh mesh = new SimpleQuadMesh(999999); + mesh.useColor(); + mesh.useTexture(); + + gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, + GL.GL_NEAREST_MIPMAP_NEAREST); + gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, + GL.GL_NEAREST_MIPMAP_NEAREST); + gl.glHint(GL2.GL_PERSPECTIVE_CORRECTION_HINT, GL2.GL_FASTEST); + gl.glHint(GL2.GL_LINE_SMOOTH_HINT, GL2.GL_NICEST); + Texture grass = TextureManager.get("texture/grass.png"); + int tex = grass.getTextureObject(gl); + + TextureCoords tc = grass.getImageTexCoords(); + // mesh.setTextureSize(tc.right(), tc.top()); + System.out.println(grass.getWidth() + " " + grass.getHeight() + " | " + + tc.left() + " " + tc.right() + " " + tc.top() + " " + + tc.bottom()); + mesh.setTextureSize(grass.getWidth(), grass.getHeight()); + for (int x = 0; x < slice.getWidth(); x++) { + for (int y = 0; y < slice.getHeight(); y++) { + for (int z = 0; z < slice.getDepth(); z++) { + mesh.setTranslation(x, y, z); + // mesh.setColor4f(0, 1, 0, 1); + mesh.setColor4f((float) Math.random(), + (float) Math.random(), (float) Math.random(), 1); + mesh.setGLTexture(tex); + if (y == 0) { + mesh.addBottomQuad(); + } + if (y == 3) { + // Math.random(); + mesh.addTopQuad(); + } + if (y < 4) { + if (x == 0) { + mesh.addLeftQuad(); + } + if (x == slice.getWidth() - 1) { + mesh.addRightQuad(); + } + if (z == 0) { + mesh.addBackQuad(); + } + if (z == slice.getDepth() - 1) { + mesh.addFrontQuad(); + } + } + } + } + } + mesh.endMesh(); + return mesh; + } + + public void render(GL glx) { + if (null == mesh) { + mesh = getMesh(glx); + } + mesh.joglRender(glx); + } + +} diff --git a/src/ru/olamedia/olacraft/render/jogl/BlockStackRenderer.java b/src/ru/olamedia/olacraft/render/jogl/BlockStackRenderer.java new file mode 100644 index 0000000..28f07fd --- /dev/null +++ b/src/ru/olamedia/olacraft/render/jogl/BlockStackRenderer.java @@ -0,0 +1,9 @@ +package ru.olamedia.olacraft.render.jogl; + +import javax.media.opengl.GLAutoDrawable; + +public class BlockStackRenderer { + public void render(GLAutoDrawable drawable) { + + } +} diff --git a/src/ru/olamedia/olacraft/render/jogl/ChunkRenderer.java b/src/ru/olamedia/olacraft/render/jogl/ChunkRenderer.java new file mode 100644 index 0000000..e24e8e9 --- /dev/null +++ b/src/ru/olamedia/olacraft/render/jogl/ChunkRenderer.java @@ -0,0 +1,146 @@ +package ru.olamedia.olacraft.render.jogl; + +import javax.media.opengl.GL; +import javax.media.opengl.GLAutoDrawable; +import javax.media.opengl.GLContext; + +import ru.olamedia.math.Box; +import ru.olamedia.math.Classifier; +import ru.olamedia.olacraft.game.Game; +import ru.olamedia.olacraft.world.chunk.BlockSlice; +import ru.olamedia.olacraft.world.chunk.Chunk; +import ru.olamedia.olacraft.world.chunk.ChunkMeshBulder; +import ru.olamedia.olacraft.world.chunk.ChunkSlice; + +public class ChunkRenderer { + private BlockSlice slice; + + public ChunkRenderer(BlockSlice slice) { + this.slice = slice; + } + + public int visibleTop = 0; + public int visibleBottom = 0; + public int visibleLeft = 0; + public int visibleRight = 0; + public int visibleFront = 0; + public int visibleBack = 0; + + public int frustumCulledChunks = 0; + public int frustumIntersectChunks = 0; + + public boolean renderChunk(Chunk chunk, boolean skipnew) { + GL gl = GLContext.getCurrentGL(); + if (!chunk.isAvailable()) { + // System.out.println("not available"); + chunk.request(); + return skipnew; + } + /* + * if (!chunk.isNeighborsAvailable()) { + * System.out.println("no neighbors"); + * chunk.requestNeighbors(); + * return; + * } + */ + // System.out.println("available"); + Box box = new Box(chunk.getX(), chunk.getY(), chunk.getZ(), chunk.getX() + chunk.getWidth(), chunk.getY() + + chunk.getHeight(), chunk.getZ() + chunk.getDepth()); + if (Game.instance.camera.frustum.quickClassify(box) == Classifier.OUTSIDE) { + frustumCulledChunks++; + return skipnew; + } + + // // boolean inside = true; + // if (Game.camera.frustum != null) { + // if (Game.camera.frustum.quickClassify(box) == + // Classifier.Classification.OUTSIDE) { + // frustumCulledChunks++; + // return; + // } + // } + // } else if (Game.camera.frustum.test(box) == Classifier.INTERSECT) { + // inside = false; + // frustumIntersectChunks++; + // } else { + // frustumCulledChunks++; + // return; + // } + if (!chunk.isMeshCostructed) { + if (skipnew) { + return skipnew; + } + } + if (!chunk.isMeshCostructed) { + ChunkMeshBulder.instance.add(chunk); + if (ChunkMeshBulder.instance.isFull()) { + skipnew = true; + } + return skipnew; + } + if (null == chunk.getMesh()) { + } else { + chunk.getMesh().joglRender(gl); + } + return skipnew; + } + + public void render(GLAutoDrawable drawable) { + + if (!ChunkMeshBulder.instance.isAlive()) { + ChunkMeshBulder.instance.start(); + } + + visibleTop = 0; + visibleBottom = 0; + visibleLeft = 0; + visibleRight = 0; + visibleFront = 0; + visibleBack = 0; + frustumCulledChunks = 0; + boolean skipnew = false; + ChunkSlice cs = slice.getChunkSlice(); + // rendering from center + int x, y, z; + int dw = cs.getWidth() / 2; + int dd = cs.getDepth() / 2; + int dh = cs.getHeight() / 2; + for (int dx = 0; dx < dw; dx++) { + x = cs.getX() + dw + dx; + for (int dz = 0; dz < dd; dz++) { + z = cs.getZ() + dd + dz; + for (int dy = 0; dy < dh; dy++) { + y = cs.getY() + dh + dy; + skipnew = renderChunk(cs.getChunk(x, y, z), skipnew); + y = cs.getY() + dh - dy - 1; + skipnew = renderChunk(cs.getChunk(x, y, z), skipnew); + } + z = cs.getZ() + dd - dz - 1; + for (int dy = 0; dy < dh; dy++) { + y = cs.getY() + dh + dy; + skipnew = renderChunk(cs.getChunk(x, y, z), skipnew); + y = cs.getY() + dh - dy - 1; + skipnew = renderChunk(cs.getChunk(x, y, z), skipnew); + } + } + x = cs.getX() + dw - dx - 1; + for (int dz = 0; dz < dd; dz++) { + z = cs.getZ() + dd + dz; + for (int dy = 0; dy < dh; dy++) { + y = cs.getY() + dh + dy; + skipnew = renderChunk(cs.getChunk(x, y, z), skipnew); + y = cs.getY() + dh - dy - 1; + skipnew = renderChunk(cs.getChunk(x, y, z), skipnew); + } + z = cs.getZ() + dd - dz - 1; + for (int dy = 0; dy < dh; dy++) { + y = cs.getY() + dh + dy; + skipnew = renderChunk(cs.getChunk(x, y, z), skipnew); + y = cs.getY() + dh - dy - 1; + skipnew = renderChunk(cs.getChunk(x, y, z), skipnew); + } + } + } + // System.out.println("visible top " + visibleTop); + } +} diff --git a/src/ru/olamedia/olacraft/render/jogl/DefaultRenderer.java b/src/ru/olamedia/olacraft/render/jogl/DefaultRenderer.java new file mode 100644 index 0000000..12c12e0 --- /dev/null +++ b/src/ru/olamedia/olacraft/render/jogl/DefaultRenderer.java @@ -0,0 +1,75 @@ +package ru.olamedia.olacraft.render.jogl; + +import com.jogamp.newt.event.KeyEvent; + +import javax.media.opengl.GLAutoDrawable; +import javax.media.opengl.glu.GLU; + +import ru.olamedia.input.KeyListener; +import ru.olamedia.input.Keyboard; +import ru.olamedia.input.MouseJail; +import ru.olamedia.input.MouseListener; +import ru.olamedia.olacraft.game.Game; + +public class DefaultRenderer implements IRenderer, KeyListener, MouseListener { + private boolean isHUDEnabled = true; + GLU glu = new GLU(); + // private static Color BLACK_TRANSPARENT = new Color(0, 0, 0, 0); + long lastHUD = System.nanoTime(); + + public DefaultRenderer() { + Keyboard.attach(this); + MouseJail.attach(this); + } + + @Override + public void render(GLAutoDrawable drawable) { + Game.client.getScene().tick(); + Game.client.getScene().render(drawable); + } + + @Override + public void onKeyPressed(String name, KeyEvent e) { + + } + + @Override + public void onKeyReleased(String name, KeyEvent e) { + // System.out.println(name); + if (name == "toggleHUD") { + isHUDEnabled = !isHUDEnabled; + } + if (name == "captureMouse") { + MouseJail.setActive(true); + } + if (name == "releaseMouse") { + MouseJail.setActive(false); + } + if (name == "toggleFrustum") { + Game.instance.camera.isFrustumVisible = !Game.instance.camera.isFrustumVisible; + } + if (name == "toggleRenderDistance") { + int renderDistance = Game.client.getScene().getRenderDistance(); + renderDistance *= 2; + if (renderDistance > 256) { + renderDistance = 32; + } + Game.client.getScene().setRenderDistance(renderDistance); + } + } + + @Override + public void onMouseMove(float dx, float dy) { + Game.instance.camera.mouseMoved(dx, dy); + } + + @Override + public void onMouseClick() { + Game.instance.player.onMouseClick(); + } + + @Override + public void init(GLAutoDrawable drawable) { + + } +} diff --git a/src/ru/olamedia/olacraft/render/jogl/IRenderer.java b/src/ru/olamedia/olacraft/render/jogl/IRenderer.java new file mode 100644 index 0000000..1ba581a --- /dev/null +++ b/src/ru/olamedia/olacraft/render/jogl/IRenderer.java @@ -0,0 +1,8 @@ +package ru.olamedia.olacraft.render.jogl; + +import javax.media.opengl.GLAutoDrawable; + +public interface IRenderer { + public void render(GLAutoDrawable drawable); + public void init(GLAutoDrawable drawable); +} diff --git a/src/ru/olamedia/olacraft/render/jogl/InventoryRenderer.java b/src/ru/olamedia/olacraft/render/jogl/InventoryRenderer.java new file mode 100644 index 0000000..46daa4a --- /dev/null +++ b/src/ru/olamedia/olacraft/render/jogl/InventoryRenderer.java @@ -0,0 +1,87 @@ +package ru.olamedia.olacraft.render.jogl; + +import javax.media.opengl.GL; +import javax.media.opengl.GL2; +import javax.media.opengl.GLAutoDrawable; + +import com.jogamp.opengl.util.texture.Texture; + +import ru.olamedia.olacraft.inventory.Inventory; +import ru.olamedia.olacraft.world.blockStack.BlockStack; +import ru.olamedia.olacraft.world.blockTypes.EmptyBlockType; +import ru.olamedia.texture.TextureManager; + +public class InventoryRenderer { + private Inventory inventory; + private BlockStackRenderer stackRenderer; + + int stackSize = 32; + int spacing = 2; + int padding = 2; + int x; + int y; + + public InventoryRenderer(Inventory inventory) { + this.inventory = inventory; + stackRenderer = new BlockStackRenderer(); + } + + public void render(GLAutoDrawable drawable) { + GL2 gl = drawable.getGL().getGL2(); + gl.glPushAttrib(GL2.GL_ALL_ATTRIB_BITS); + int vWidth = drawable.getWidth(); + int vHeight = drawable.getHeight(); + // Draw GUI + + int width = stackSize * Inventory.BIND_NUM + spacing * (Inventory.BIND_NUM - 1) + padding * 2; + int height = stackSize + padding * 2; + x = (vWidth - width) / 2; + y = (vHeight - height) - 10; + gl.glRecti(x, y, x + width, y + height); + // Draw stacks + gl.glEnable(GL2.GL_TEXTURE_2D); + for (int i = 0; i < Inventory.BIND_NUM; i++) { + renderStack(i, drawable); + } + gl.glPopAttrib(); + } + + public void renderStack(int i, GLAutoDrawable drawable) { + GL2 gl = drawable.getGL().getGL2(); + BlockStack stack = inventory.binded[i]; + int sx = x + padding + stackSize * i + spacing * i; + int sy = y + padding; + if (null != stack && !(stack.block.getType() instanceof EmptyBlockType)) { + Texture tex = TextureManager.get(stack.block.getType().getStackTextureFile()); + if (null != tex) { + tex.bind(gl); + gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, GL.GL_NEAREST); + gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, GL.GL_NEAREST_MIPMAP_NEAREST); + gl.glColor3f(1, 1, 1); + int x1 = sx; + int x2 = sx + stackSize; + int y1 = sy; + int y2 = sy + stackSize; + gl.glBegin(GL2.GL_QUADS); + { + gl.glTexCoord2f(0, 0); + gl.glVertex2f(x1, y1); + gl.glTexCoord2f(0, 1); + gl.glVertex2f(x1, y2); + gl.glTexCoord2f(1, 1); + gl.glVertex2f(x2, y2); + gl.glTexCoord2f(1, 0); + gl.glVertex2f(x2, y1); + } + gl.glEnd(); + // gl.glRecti(sx, sy, sx + stackSize, sy + stackSize); + } + } else { + gl.glDisable(GL2.GL_TEXTURE_2D); + float gray = 0.5f; + gl.glColor3f(gray, gray, gray); + gl.glRecti(sx, sy, sx + stackSize, sy + stackSize); + gl.glEnable(GL2.GL_TEXTURE_2D); + } + } +} diff --git a/src/ru/olamedia/olacraft/render/jogl/PlaneRenderer.java b/src/ru/olamedia/olacraft/render/jogl/PlaneRenderer.java new file mode 100644 index 0000000..754a093 --- /dev/null +++ b/src/ru/olamedia/olacraft/render/jogl/PlaneRenderer.java @@ -0,0 +1,102 @@ +package ru.olamedia.olacraft.render.jogl; + +import javax.media.opengl.GL2; +import javax.media.opengl.GLAutoDrawable; + +import ru.olamedia.math.Plane; + +public class PlaneRenderer { + private static float getZ(Plane p, float x, float y) { + return -(p.n.x * x + p.n.y * y + p.d) / p.n.z; + } + + private static float getY(Plane p, float x, float z) { + return -(p.n.x * x + p.n.z * z + p.d) / p.n.y; + } + + private static float getX(Plane p, float y, float z) { + return -(p.n.y * y + p.n.z * z + p.d) / p.n.x; + } + + public static void render(Plane p, GLAutoDrawable drawable) { + GL2 gl = drawable.getGL().getGL2(); + float size = 100; + float step = size / 5; + for (float x = -size; x <= size; x += step) { + for (float y = -size; y <= size; y += step) { + // nx * x + ny * y + nz * z + d = 0 + // (z = nx * x + ny * y + d) / nz + float z = getZ(p, x, y); + float x2 = x + step; + float y2 = y; + float z2 = getZ(p, x2, y2); + float x3 = x + step; + float y3 = y + step; + float z3 = getZ(p, x3, y3); + float x4 = x; + float y4 = y + step; + float z4 = getZ(p, x4, y4); + gl.glPolygonMode(GL2.GL_FRONT_AND_BACK, GL2.GL_LINE); + gl.glBegin(GL2.GL_QUADS); + { + gl.glVertex3f(x, y, z); + gl.glVertex3f(x2, y2, z2); + gl.glVertex3f(x3, y3, z3); + gl.glVertex3f(x4, y4, z4); + } + gl.glEnd(); + } + } + for (float x = -size; x <= size; x += step) { + for (float z = -size; z <= size; z += step) { + // nx * x + ny * y + nz * z + d = 0 + // (z = nx * x + ny * y + d) / nz + float y = getY(p, x, z); + float x2 = x + step; + float z2 = z; + float y2 = getY(p, x2, z2); + float x3 = x + step; + float z3 = z + step; + float y3 = getY(p, x3, z3); + float x4 = x; + float z4 = z + step; + float y4 = getY(p, x4, z4); + gl.glPolygonMode(GL2.GL_FRONT_AND_BACK, GL2.GL_LINE); + gl.glBegin(GL2.GL_QUADS); + { + gl.glVertex3f(x, y, z); + gl.glVertex3f(x2, y2, z2); + gl.glVertex3f(x3, y3, z3); + gl.glVertex3f(x4, y4, z4); + } + gl.glEnd(); + } + } + + for (float y = -size; y <= size; y += step) { + for (float z = -size; z <= size; z += step) { + // nx * x + ny * y + nz * z + d = 0 + // (z = nx * x + ny * y + d) / nz + float x = getX(p, y, z); + float y2 = y + step; + float z2 = z; + float x2 = getX(p, y2, z2); + float y3 = y + step; + float z3 = z + step; + float x3 = getX(p, y3, z3); + float y4 = y; + float z4 = z + step; + float x4 = getX(p, y4, z4); + gl.glPolygonMode(GL2.GL_FRONT_AND_BACK, GL2.GL_LINE); + gl.glBegin(GL2.GL_QUADS); + { + gl.glVertex3f(x, y, z); + gl.glVertex3f(x2, y2, z2); + gl.glVertex3f(x3, y3, z3); + gl.glVertex3f(x4, y4, z4); + } + gl.glEnd(); + } + } + } +} diff --git a/src/ru/olamedia/olacraft/render/jogl/VectorRenderer.java b/src/ru/olamedia/olacraft/render/jogl/VectorRenderer.java new file mode 100644 index 0000000..180ec2a --- /dev/null +++ b/src/ru/olamedia/olacraft/render/jogl/VectorRenderer.java @@ -0,0 +1,20 @@ +package ru.olamedia.olacraft.render.jogl; + +import javax.media.opengl.GL2; +import javax.media.opengl.GLAutoDrawable; + +import ru.olamedia.math.Vector3f; + +public class VectorRenderer { + public static void render(Vector3f point, Vector3f v, GLAutoDrawable drawable) { + GL2 gl = drawable.getGL().getGL2(); + gl.glDisable(GL2.GL_TEXTURE_2D); + gl.glColor3f(1, 0, 0); + gl.glBegin(GL2.GL_LINES); + { + gl.glVertex3f(point.x, point.y, point.z); + gl.glVertex3f(point.x + v.x, point.y + v.y, point.z + v.z); + } + gl.glEnd(); + } +} diff --git a/src/ru/olamedia/olacraft/render/jogl/joglViewport.java b/src/ru/olamedia/olacraft/render/jogl/joglViewport.java new file mode 100644 index 0000000..b3da2ce --- /dev/null +++ b/src/ru/olamedia/olacraft/render/jogl/joglViewport.java @@ -0,0 +1,24 @@ +package ru.olamedia.olacraft.render.jogl; + +import java.awt.Font; + +import javax.media.opengl.GLAutoDrawable; + +import com.jogamp.opengl.util.awt.TextRenderer; + +public class joglViewport { + private GLAutoDrawable drawable; + private TextRenderer sans11; + + public joglViewport(GLAutoDrawable drawable) { + this.drawable = drawable; + sans11 = new TextRenderer(new Font("SansSerif", Font.PLAIN, 11)); + } + + public void drawText(String text, int x, int y) { + sans11.setColor(1, 1, 1, 0.7f); + sans11.beginRendering(drawable.getWidth(), drawable.getHeight()); + sans11.draw(text, x, y); + sans11.endRendering(); + } +} diff --git a/src/ru/olamedia/olacraft/render/jogl/package-info.java b/src/ru/olamedia/olacraft/render/jogl/package-info.java new file mode 100644 index 0000000..73b0ace --- /dev/null +++ b/src/ru/olamedia/olacraft/render/jogl/package-info.java @@ -0,0 +1,8 @@ +/** + * + */ +/** + * @author olamedia + * + */ +package ru.olamedia.olacraft.render.jogl;
\ No newline at end of file diff --git a/src/ru/olamedia/olacraft/scene/GameScene.java b/src/ru/olamedia/olacraft/scene/GameScene.java new file mode 100644 index 0000000..618e270 --- /dev/null +++ b/src/ru/olamedia/olacraft/scene/GameScene.java @@ -0,0 +1,252 @@ +package ru.olamedia.olacraft.scene; + +import java.lang.management.ManagementFactory; +import java.lang.management.MemoryUsage; +import java.util.HashMap; + +import javax.media.opengl.GL2; +import javax.media.opengl.GLAutoDrawable; +import javax.media.opengl.glu.GLU; +import javax.media.opengl.glu.GLUquadric; + +import org.ode4j.ode.DBody; + +import com.jogamp.opengl.util.PMVMatrix; + +import ru.olamedia.Options; +import ru.olamedia.liveEntity.LiveEntity; +import ru.olamedia.olacraft.game.Game; +import ru.olamedia.olacraft.physics.GamePhysicsWorld; +import ru.olamedia.olacraft.render.jogl.ChunkRenderer; +import ru.olamedia.olacraft.render.jogl.InventoryRenderer; +import ru.olamedia.olacraft.render.jogl.joglViewport; +import ru.olamedia.olacraft.weapon.Bullet; +import ru.olamedia.olacraft.weapon.BulletScene; +import ru.olamedia.olacraft.world.blockTypes.AbstractBlockType; +import ru.olamedia.olacraft.world.blockTypes.GrassBlockType; +import ru.olamedia.olacraft.world.chunk.BlockSlice; +import ru.olamedia.olacraft.world.provider.WorldProvider; +import ru.olamedia.player.Player; +import ru.olamedia.vbo.VBO; + +public class GameScene { + + private PMVMatrix matrix; + + private HashMap<Integer, LiveEntity> liveEntities = new HashMap<Integer, LiveEntity>(); + WorldProvider provider; + private int renderDistance = Options.renderDistance; + private joglViewport viewport; + private BulletScene bullets = new BulletScene(); + private GamePhysicsWorld physics = new GamePhysicsWorld(); + + private VBO testObject; + + private boolean isInitialized = false; + BlockSlice viewSlice; + + public GameScene(WorldProvider provider) { + this.provider = provider; + setRenderDistance(renderDistance); + } + + public void addBullet(Bullet b) { + bullets.add(b); + DBody body = physics.createBody(); + body.setPosition(b.location.x, b.location.y, b.location.z); + body.setLinearVel(b.velocity.x, b.velocity.y, b.velocity.z); + /* + * DMass mass = OdeHelper.createMass(); + * mass.setMass(10); + * mass.setI(OdeHelper.c); + * body.setMass(mass); + */ + b.body = body; + } + + public int getBulletsCount() { + return bullets.getCount(); + } + + public void init(GLAutoDrawable drawable) { + if (isInitialized) { + return; + } + isInitialized = true; + registerTextures(); + viewport = new joglViewport(drawable); + testObject = new VBO(drawable); + } + + private void registerTextures() { + AbstractBlockType t; + t = new GrassBlockType(); + t.register(); + } + + /** + * @return the renderDistance + */ + public int getRenderDistance() { + return renderDistance; + } + + /** + * @param renderDistance + * the renderDistance to set + */ + public void setRenderDistance(int renderDistance) { + this.renderDistance = renderDistance; + viewSlice = new BlockSlice(provider, renderDistance, renderDistance * 2, renderDistance); + blockRenderer = new ChunkRenderer(viewSlice); + } + + ChunkRenderer blockRenderer = new ChunkRenderer(viewSlice); + GLU glu = new GLU(); + + public void registerLiveEntity(LiveEntity entity) { + // liveEntityIncrement++; + // entity.setId(liveEntityIncrement); + liveEntities.put(entity.getConnectionId(), entity); + } + + private InventoryRenderer inventoryRenderer; + + private Player player; + + public void registerPlayer(LiveEntity player) { + inventoryRenderer = new InventoryRenderer(player.getInventory()); + this.player = (Player) player; + } + + public LiveEntity getLiveEntity(int connectionId) { + if (liveEntities.containsKey(connectionId)) { + return liveEntities.get(connectionId); + } + return null; + } + + public HashMap<Integer, LiveEntity> getLiveEntities() { + return liveEntities; + } + + public void tick() { + Game.instance.tick(); + float aspect = Game.Display.getAspect(); + Game.instance.camera.setAspect(aspect); + // bullets.update(Game.instance.getDelta()); + physics.getWorld().step(Game.instance.getDelta()); + } + + public void render(GLAutoDrawable drawable) { + if (!Game.instance.isRunning()) { + // not running, just clear screen + GL2 gl = drawable.getGL().getGL2(); + gl.glClear(GL2.GL_COLOR_BUFFER_BIT | GL2.GL_DEPTH_BUFFER_BIT); + gl.glClearColor(49f / 255f, 49f / 255f, 49f / 255f, 1); + return; + } + init(drawable); + GL2 gl = drawable.getGL().getGL2(); + gl.glClear(GL2.GL_COLOR_BUFFER_BIT | GL2.GL_DEPTH_BUFFER_BIT); + gl.glClearColor(49f / 255f, 119f / 255f, 243f / 255f, 1); + // GOING 3D + gl.glPushMatrix(); + Game.instance.camera.setUp(drawable); + viewSlice.setCenter((int) Game.instance.camera.getX(), (int) Game.instance.camera.getY(), + (int) Game.instance.camera.getZ()); + // RENDER BLOCKS + gl.glPushAttrib(GL2.GL_ALL_ATTRIB_BITS); + gl.glColor4f(0f, 1f, 0, 1); + gl.glEnable(GL2.GL_DEPTH_TEST); + gl.glShadeModel(GL2.GL_FLAT); + gl.glCullFace(GL2.GL_BACK); + // gl.glEnable(GL2.GL_FOG); + // gl.glFogf(GL2.GL_FOG_MODE, GL2.GL_LINEAR); + // gl.glFogf(GL2.GL_FOG_MODE, GL2.GL_EXP); + // gl.glFogf(GL2.GL_FOG_START, renderDistance / 2 - renderDistance / + // 10); + // gl.glFogf(GL2.GL_FOG_END, renderDistance / 2); + // gl.glFogf(GL2.GL_FOG_DENSITY, 0.002f); + // new float[] { 49f / 255f, 119f / 255f, 243f / 255f } + // gl.glFogfv(GL2.GL_FOG_COLOR, new float[] { 1, 1, 1, 0.2f }, 0); + blockRenderer.render(drawable); + gl.glPopAttrib(); + // RENDER ANYTHING ELSE + gl.glPushAttrib(GL2.GL_ALL_ATTRIB_BITS); + GLUquadric qobj0 = glu.gluNewQuadric(); + glu.gluQuadricDrawStyle(qobj0, GLU.GLU_FILL); + glu.gluQuadricNormals(qobj0, GLU.GLU_SMOOTH); + for (LiveEntity entity : liveEntities.values()) { + gl.glPushMatrix(); + gl.glTranslatef(entity.getX(), entity.getCameraY(), entity.getZ()); + glu.gluSphere(qobj0, 0.5f, 10, 10); + gl.glPopMatrix(); + } + gl.glPopAttrib(); + // bullets.render(drawable); + gl.glPopMatrix(); + + testObject.render(); + + // GOIND 2D + gl.glMatrixMode(GL2.GL_PROJECTION); + gl.glLoadIdentity(); + int width = Game.Display.getWidth(); + int height = Game.Display.getHeight(); + glu.gluOrtho2D(0, width, height, 0); + gl.glMatrixMode(GL2.GL_MODELVIEW); + gl.glPushMatrix(); + // renderHUD(); + // MAP++ + gl.glPushAttrib(GL2.GL_ALL_ATTRIB_BITS); + gl.glPolygonMode(GL2.GL_FRONT_AND_BACK, GL2.GL_FILL); + int msz = 100; + gl.glColor4f(0.3f, 0.3f, 0.3f, 0.7f); + gl.glRectf(width - msz - 12, 8, width - 8, msz + 12); + gl.glColor4f(0.9f, 0.9f, 0.9f, 1); + gl.glRectf(width - msz - 10, 10, width - 10, msz + 10); + gl.glColor4f(0.0f, 0.0f, 0.0f, 0.9f); + /* + * for (int mx = 0; mx < msz; mx++) { + * for (int mz = 0; mz < msz; mz++) { + * float h = (float) viewSlice + * .getHighest((int) (mx - msz / 2 + player.getX()), (int) (mz - msz / 2 + * + player.getZ())); + * gl.glColor4f(h / 128, h / 128, h / 128, 1f); + * gl.glRectf(width - msz - 10 + mx, 10 + mz, width - msz - 10 + mx + 1, + * 10 + mz + 1); + * } + * } + */ + // MAP-- + // crosshair + gl.glColor4f(1f, 1f, 1f, 0.7f); + gl.glRectf(width / 2 - 1, height / 2 - 10, width / 2 + 1, height / 2 + 10); // vertical + gl.glRectf(width / 2 - 10, height / 2 - 1, width / 2 + 10, height / 2 + 1); // horizontal + + // inventoryprivate PMVMatrix matrix; + if (null != inventoryRenderer) { + inventoryRenderer.render(drawable); + } + + viewport.drawText("avg fps: " + (int) Game.timer.getAvgFps(), 10, height - 20); + viewport.drawText("fps: " + (int) Game.timer.getFps(), 10, height - 35); + MemoryUsage heap = ManagementFactory.getMemoryMXBean().getHeapMemoryUsage(); + viewport.drawText("mem: " + (heap.getUsed() / (1024 * 1024)) + "/" + (heap.getMax() / (1024 * 1024)), 10, + height - 50); + + viewport.drawText("y: " + Game.instance.player.getY(), width - msz - 10, height - msz - 25); + viewport.drawText("x: " + Game.instance.player.getX(), width - msz - 10, height - msz - 40); + viewport.drawText("z: " + Game.instance.player.getZ(), width - msz - 10, height - msz - 55); + viewport.drawText("players: " + liveEntities.size(), width - msz - 10, height - msz - 70); + viewport.drawText("bullets: " + getBulletsCount(), width - msz - 10, height - msz - 95); + viewport.drawText("inAir: " + Game.instance.player.inAir(), width - msz - 10, height - msz - 110); + viewport.drawText("rdistance: " + renderDistance, width - msz - 10, height - msz - 155); + + viewport.drawText("cam x: " + Game.instance.camera.getX(), width - msz - 10, height - msz - 170); + gl.glPopAttrib(); + gl.glPopMatrix(); + gl.glFlush(); + } +} diff --git a/src/ru/olamedia/olacraft/scene/package-info.java b/src/ru/olamedia/olacraft/scene/package-info.java new file mode 100644 index 0000000..660e324 --- /dev/null +++ b/src/ru/olamedia/olacraft/scene/package-info.java @@ -0,0 +1,8 @@ +/** + * + */ +/** + * @author olamedia + * + */ +package ru.olamedia.olacraft.scene;
\ No newline at end of file diff --git a/src/ru/olamedia/olacraft/weapon/Bullet.java b/src/ru/olamedia/olacraft/weapon/Bullet.java new file mode 100644 index 0000000..6292bf2 --- /dev/null +++ b/src/ru/olamedia/olacraft/weapon/Bullet.java @@ -0,0 +1,51 @@ +package ru.olamedia.olacraft.weapon; + +import javax.media.opengl.GL2; +import javax.media.opengl.GLAutoDrawable; +import javax.media.opengl.glu.GLU; +import javax.media.opengl.glu.GLUquadric; +import javax.vecmath.Point3f; +import javax.vecmath.Vector3f; + +import org.ode4j.ode.DBody; + +public class Bullet { + public Point3f location = new Point3f(); + public Vector3f velocity = new Vector3f(); + public Vector3f acceleration = new Vector3f(0, -0.98f, 0); + public DBody body; + public float width = 0.05f; + public float height = 0.05f; + public float depth = 0.25f; + public boolean toRemove = false; + private static GLU glu = new GLU(); + + public void update(float deltams) { + // acceleration.set(velocity); + // acceleration.negate(); + // acceleration.scale(0.1f); + // acceleration.y += -0.98f; + // velocity.x += acceleration.x * deltams; + // velocity.y += acceleration.y * deltams; + // velocity.z += acceleration.z * deltams; + // float step = deltams; + // location.x += velocity.x * deltams; + // location.y += velocity.y * deltams; + // location.z += velocity.z * deltams; + if (body.getPosition().get1() < 0 || body.getPosition().get1() > 100) { + // FIXME + toRemove = true; + } + } + + public void render(GLAutoDrawable drawable) { + GL2 gl = drawable.getGL().getGL2(); + gl.glPushMatrix(); + gl.glTranslated(body.getPosition().get0(), body.getPosition().get1(), body.getPosition().get2()); + GLUquadric bulletGeom = glu.gluNewQuadric(); + glu.gluQuadricDrawStyle(bulletGeom, GLU.GLU_FILL); + glu.gluQuadricNormals(bulletGeom, GLU.GLU_SMOOTH); + glu.gluDisk(bulletGeom, 0.3, 0.4, 5, 5); + gl.glPopMatrix(); + } +} diff --git a/src/ru/olamedia/olacraft/weapon/BulletScene.java b/src/ru/olamedia/olacraft/weapon/BulletScene.java new file mode 100644 index 0000000..1e5ea05 --- /dev/null +++ b/src/ru/olamedia/olacraft/weapon/BulletScene.java @@ -0,0 +1,35 @@ +package ru.olamedia.olacraft.weapon; + +import java.util.ArrayList; +import java.util.List; + +import javax.media.opengl.GLAutoDrawable; + +public class BulletScene { + private List<Bullet> bullets = new ArrayList<Bullet>(); + + public void add(Bullet b) { + bullets.add(b); + } + + public int getCount(){ + return bullets.size(); + } + + public void update(float deltas) { + for (int i = 0; i < bullets.size(); i++) { + Bullet b = bullets.get(i); + b.update(deltas); + if (b.toRemove) { + bullets.remove(b); + i--; + } + } + } + + public void render(GLAutoDrawable drawable) { + for (Bullet b : bullets) { + b.render(drawable); + } + } +} diff --git a/src/ru/olamedia/olacraft/weapon/package-info.java b/src/ru/olamedia/olacraft/weapon/package-info.java new file mode 100644 index 0000000..89ca87c --- /dev/null +++ b/src/ru/olamedia/olacraft/weapon/package-info.java @@ -0,0 +1,8 @@ +/** + * + */ +/** + * @author olamedia + * + */ +package ru.olamedia.olacraft.weapon;
\ No newline at end of file diff --git a/src/ru/olamedia/olacraft/world/World.java b/src/ru/olamedia/olacraft/world/World.java new file mode 100644 index 0000000..e3d25f2 --- /dev/null +++ b/src/ru/olamedia/olacraft/world/World.java @@ -0,0 +1,12 @@ +package ru.olamedia.olacraft.world; + +import ru.olamedia.olacraft.world.block.BlockRegistry; +import ru.olamedia.olacraft.world.blockTypes.GrassBlockType; + +public class World { + private BlockRegistry blockRegistry; + public void setup() { + blockRegistry = new BlockRegistry(); + blockRegistry.registerBlockType(GrassBlockType.class); + } +} diff --git a/src/ru/olamedia/olacraft/world/WorldInfo.java b/src/ru/olamedia/olacraft/world/WorldInfo.java new file mode 100644 index 0000000..797339f --- /dev/null +++ b/src/ru/olamedia/olacraft/world/WorldInfo.java @@ -0,0 +1,11 @@ +package ru.olamedia.olacraft.world; + +import java.io.Serializable; + +public class WorldInfo implements Serializable { + private static final long serialVersionUID = -3669317489158639456L; + public String name = "world"; + public int minHeight = -128; + public int maxHeight = 127; + public float gravity = 9.81f; +} diff --git a/src/ru/olamedia/olacraft/world/block/Block.java b/src/ru/olamedia/olacraft/world/block/Block.java new file mode 100644 index 0000000..a48c9df --- /dev/null +++ b/src/ru/olamedia/olacraft/world/block/Block.java @@ -0,0 +1,111 @@ +package ru.olamedia.olacraft.world.block; + +import ru.olamedia.olacraft.world.blockTypes.BlockType; +import ru.olamedia.olacraft.world.blockTypes.EmptyBlockType; +import ru.olamedia.olacraft.world.provider.WorldProvider; + +public class Block { + private WorldProvider provider; + private int x; + private int y; + private int z; + + /** + * Inventory block + */ + public Block() { + this.provider = null; + this.x = 0; + this.y = 0; + this.z = 0; + } + + public void putIntoWorld(WorldProvider worldProvider, int x, int y, int z) { + this.provider = worldProvider; + this.x = x; + this.y = y; + this.z = z; + } + + public Block(WorldProvider worldProvider, int x, int y, int z) { + putIntoWorld(worldProvider, x, y, z); + } + + /** + * @return the x + */ + public int getX() { + return x; + } + + /** + * @param x + * the x to set + */ + public void setX(int x) { + this.x = x; + } + + /** + * @return the y + */ + public int getY() { + return y; + } + + /** + * @param y + * the y to set + */ + public void setY(int y) { + this.y = y; + } + + /** + * @return the z + */ + public int getZ() { + return z; + } + + /** + * @param z + * the z to set + */ + public void setZ(int z) { + this.z = z; + } + + public boolean isEmpty() { + return provider.isEmptyBlock(x, y, z); + } + + public Block getNeighbor(int dx, int dy, int dz) { + return new Block(provider, x + dx, y + dy, z + dz); + } + + public Block[] getNeighbors() { + return new Block[] { + // + getNeighbor(1, 0, 0),// + getNeighbor(0, 1, 0),// + getNeighbor(0, 0, 1),// + getNeighbor(-1, 0, 0),// + getNeighbor(0, -1, 0),// + getNeighbor(0, 0, -1),// + }; + } + + private BlockType type; + + public void setType(BlockType type) { + this.type = type; + } + + public BlockType getType() { + if (null == type) { + type = new EmptyBlockType(); + } + return type; + } +} diff --git a/src/ru/olamedia/olacraft/world/block/BlockRegistry.java b/src/ru/olamedia/olacraft/world/block/BlockRegistry.java new file mode 100644 index 0000000..19ccc94 --- /dev/null +++ b/src/ru/olamedia/olacraft/world/block/BlockRegistry.java @@ -0,0 +1,46 @@ +package ru.olamedia.olacraft.world.block; + +import java.util.HashMap; + +import ru.olamedia.olacraft.world.blockTypes.BlockType; + +public class BlockRegistry { + + private HashMap<Integer, String> names = new HashMap<Integer, String>(); + private HashMap<Integer, BlockType> types = new HashMap<Integer, BlockType>(); + private int autoincrement = 0; + + private BlockRegistry worldRegistry; + + public BlockRegistry() { + } + + public BlockType getBlockType(int id) { + return types.get(id); + } + + public String getBlockHumanId(int id) { + return names.get(id); + } + + public int registerBlockType(@SuppressWarnings("rawtypes") Class type) { + if (type.isInstance(BlockType.class)) { + autoincrement++; + int id = autoincrement; + String classId = type.getName(); + names.put(id, classId); + // types.put(id, type); + return autoincrement; + } + return 0; + } + + public BlockRegistry getWorldRegistry() { + return worldRegistry; + } + + public void setWorldRegistry(BlockRegistry worldRegistry) { + this.worldRegistry = worldRegistry; + } + +} diff --git a/src/ru/olamedia/olacraft/world/block/package-info.java b/src/ru/olamedia/olacraft/world/block/package-info.java new file mode 100644 index 0000000..0924926 --- /dev/null +++ b/src/ru/olamedia/olacraft/world/block/package-info.java @@ -0,0 +1,8 @@ +/** + * + */ +/** + * @author olamedia + * + */ +package ru.olamedia.olacraft.world.block;
\ No newline at end of file diff --git a/src/ru/olamedia/olacraft/world/blockStack/BlockStack.java b/src/ru/olamedia/olacraft/world/blockStack/BlockStack.java new file mode 100644 index 0000000..57258ef --- /dev/null +++ b/src/ru/olamedia/olacraft/world/blockStack/BlockStack.java @@ -0,0 +1,63 @@ +package ru.olamedia.olacraft.world.blockStack; + +import ru.olamedia.olacraft.world.block.Block; + +public class BlockStack { + public Block block; + public int count; + + public BlockStack(Block block, int count) { + this.block = block; + this.count = count; + } + + public BlockStack get() { + return get(1); + } + + public BlockStack get(int getcount) { + int c = 0; + if (count >= getcount) { + c = getcount; + count -= getcount; + } else { + c = count; + count = 0; + } + return new BlockStack(block, c); + } + + public BlockStack getAll() { + int c = count; + count = 0; + return new BlockStack(block, c); + } + + /** + * + * @return Remaining BlockStack + */ + public BlockStack putStack(BlockStack stack) { + + if (block.getType() == stack.block.getType()) { + int max = block.getType().getMaxStack(); + // Stack + int total = count + stack.count; + if (total < max) { + count = total; + return new BlockStack(block, 0); + } else { + BlockStack remains = new BlockStack(block, total - max); + count = max; + return remains; + } + } else { + // Replace + BlockStack remains = new BlockStack(block, count); + block = stack.block; + count = stack.count; + return remains; + } + } + +} diff --git a/src/ru/olamedia/olacraft/world/blockStack/package-info.java b/src/ru/olamedia/olacraft/world/blockStack/package-info.java new file mode 100644 index 0000000..933dc87 --- /dev/null +++ b/src/ru/olamedia/olacraft/world/blockStack/package-info.java @@ -0,0 +1,8 @@ +/** + * + */ +/** + * @author olamedia + * + */ +package ru.olamedia.olacraft.world.blockStack;
\ No newline at end of file diff --git a/src/ru/olamedia/olacraft/world/blockTypes/AbstractBlockType.java b/src/ru/olamedia/olacraft/world/blockTypes/AbstractBlockType.java new file mode 100644 index 0000000..6e2a86f --- /dev/null +++ b/src/ru/olamedia/olacraft/world/blockTypes/AbstractBlockType.java @@ -0,0 +1,86 @@ +package ru.olamedia.olacraft.world.blockTypes; + +import com.jogamp.opengl.util.texture.Texture; + +import ru.olamedia.texture.TextureManager; + +public abstract class AbstractBlockType implements BlockType { + + @Override + abstract public String getName(); + + @Override + public int getMaxStack() { + return 64; + } + + @Override + abstract public String getStackTextureFile(); + + @Override + abstract public String getTopTextureFile(); + + @Override + public String getBottomTextureFile() { + return this.getTopTextureFile(); + } + + @Override + public String getLeftTextureFile() { + return this.getFrontTextureFile(); + } + + @Override + public String getRightTextureFile() { + return this.getFrontTextureFile(); + } + + @Override + public String getFrontTextureFile() { + return this.getTopTextureFile(); + } + + @Override + public String getBackTextureFile() { + return this.getFrontTextureFile(); + } + + @Override + public Texture getTopTexture() { + return TextureManager.get(this.getTopTextureFile()); + } + + @Override + public Texture getBottomTexture() { + return TextureManager.get(this.getBottomTextureFile()); + } + + @Override + public Texture getLeftTexture() { + return TextureManager.get(this.getLeftTextureFile()); + } + + @Override + public Texture getRightTexture() { + return TextureManager.get(this.getRightTextureFile()); + } + + @Override + public Texture getFrontTexture() { + return TextureManager.get(this.getFrontTextureFile()); + } + + @Override + public Texture getBackTexture() { + return TextureManager.get(this.getBackTextureFile()); + } + + public void register(){ + getBackTexture(); + getBottomTexture(); + getFrontTexture(); + getLeftTexture(); + getRightTexture(); + getTopTexture(); + } +} diff --git a/src/ru/olamedia/olacraft/world/blockTypes/BlockType.java b/src/ru/olamedia/olacraft/world/blockTypes/BlockType.java new file mode 100644 index 0000000..0bda2eb --- /dev/null +++ b/src/ru/olamedia/olacraft/world/blockTypes/BlockType.java @@ -0,0 +1,21 @@ +package ru.olamedia.olacraft.world.blockTypes; + +import com.jogamp.opengl.util.texture.Texture; + +public interface BlockType { + public String getName(); + public int getMaxStack(); + public String getStackTextureFile(); + public String getTopTextureFile(); + public String getBottomTextureFile(); + public String getLeftTextureFile(); + public String getRightTextureFile(); + public String getFrontTextureFile(); + public String getBackTextureFile(); + public Texture getTopTexture(); + public Texture getBottomTexture(); + public Texture getLeftTexture(); + public Texture getRightTexture(); + public Texture getFrontTexture(); + public Texture getBackTexture(); +} diff --git a/src/ru/olamedia/olacraft/world/blockTypes/EmptyBlockType.java b/src/ru/olamedia/olacraft/world/blockTypes/EmptyBlockType.java new file mode 100644 index 0000000..4073356 --- /dev/null +++ b/src/ru/olamedia/olacraft/world/blockTypes/EmptyBlockType.java @@ -0,0 +1,23 @@ +package ru.olamedia.olacraft.world.blockTypes; + +public class EmptyBlockType extends AbstractBlockType { + @Override + public String getName() { + return ""; + } + + @Override + public int getMaxStack() { + return 64; + } + + @Override + public String getStackTextureFile() { + return "texture/empty.png"; + } + + @Override + public String getTopTextureFile() { + return "texture/empty.png"; + } +} diff --git a/src/ru/olamedia/olacraft/world/blockTypes/GrassBlockType.java b/src/ru/olamedia/olacraft/world/blockTypes/GrassBlockType.java new file mode 100644 index 0000000..816b283 --- /dev/null +++ b/src/ru/olamedia/olacraft/world/blockTypes/GrassBlockType.java @@ -0,0 +1,28 @@ +package ru.olamedia.olacraft.world.blockTypes; + +public class GrassBlockType extends AbstractBlockType { + @Override + public String getName() { + return "Grass"; + } + + @Override + public int getMaxStack() { + return 64; + } + + @Override + public String getStackTextureFile() { + return "texture/terrain-grassdarkgreen.png"; + } + + @Override + public String getTopTextureFile() { + return "texture/terrain-grassdarkgreen.png"; + } + + @Override + public String getFrontTextureFile() { + return "texture/terrain-glong-darkgreen-dirt.png"; + } +} diff --git a/src/ru/olamedia/olacraft/world/blockTypes/GravelBlockType.java b/src/ru/olamedia/olacraft/world/blockTypes/GravelBlockType.java new file mode 100644 index 0000000..354d383 --- /dev/null +++ b/src/ru/olamedia/olacraft/world/blockTypes/GravelBlockType.java @@ -0,0 +1,23 @@ +package ru.olamedia.olacraft.world.blockTypes; + +public class GravelBlockType extends AbstractBlockType { + @Override + public String getName() { + return "Gravel"; + } + + @Override + public int getMaxStack() { + return 64; + } + + @Override + public String getStackTextureFile() { + return "texture/gravel.png"; + } + + @Override + public String getTopTextureFile() { + return "texture/gravel.png"; + } +} diff --git a/src/ru/olamedia/olacraft/world/blockTypes/package-info.java b/src/ru/olamedia/olacraft/world/blockTypes/package-info.java new file mode 100644 index 0000000..a49dda8 --- /dev/null +++ b/src/ru/olamedia/olacraft/world/blockTypes/package-info.java @@ -0,0 +1,8 @@ +/** + * + */ +/** + * @author olamedia + * + */ +package ru.olamedia.olacraft.world.blockTypes;
\ No newline at end of file diff --git a/src/ru/olamedia/olacraft/world/chunk/BlockSlice.java b/src/ru/olamedia/olacraft/world/chunk/BlockSlice.java new file mode 100644 index 0000000..ca4c92a --- /dev/null +++ b/src/ru/olamedia/olacraft/world/chunk/BlockSlice.java @@ -0,0 +1,164 @@ +package ru.olamedia.olacraft.world.chunk; + +import ru.olamedia.olacraft.world.provider.WorldProvider; + +public class BlockSlice { + protected WorldProvider provider; + protected int leftX; + protected int bottomY; + protected int backZ; + protected int width; + protected int height; + protected int depth; + + protected ChunkSlice chunkSlice; + + // Memory leak: + //protected int[][] highest = new int[256][256]; + + public void invalidateCache(){ + //highest = new int[256][256]; + } + +/* public int getHighest(int blockX, int blockZ) { + if (highest[blockX - leftX][blockZ - backZ] > 0){ + return highest[blockX - leftX][blockZ - backZ]; + } + for (int y = 0; y < 128; y++) { + if (provider.isEmptyBlock(blockX, y, blockZ)){ + highest[blockX - leftX][blockZ - backZ] = y; + return y; + } + } + return 0; + }*/ + + /** + * + * @param provider + * @param width + * (blocks) + * @param height + * (blocks) + * @param depth + * (blocks) + */ + public BlockSlice(WorldProvider provider, int width, int height, int depth) { + this.provider = provider; + this.width = width; + this.height = height; + this.depth = depth; + } + + public ChunkSlice getChunkSlice() { + if (null == chunkSlice) { + chunkSlice = new ChunkSlice(provider, width / 16, height / 16, depth / 16); + } + int x = Chunk.v(leftX); + int y = Chunk.v(bottomY); + int z = Chunk.v(backZ); + chunkSlice.setLocation(x, y, z); + return chunkSlice; + } + + public int getTotalBlocks() { + return getWidth() * getHeight() * getDepth(); + } + + /** + * @return the width (blocks) + */ + public int getWidth() { + return width; + } + + /** + * @param width + * (blocks) + */ + public void setWidth(int width) { + this.width = width; + } + + /** + * @return the height (blocks) + */ + public int getHeight() { + return height; + } + + /** + * @param height + * (blocks) + */ + public void setHeight(int height) { + this.height = height; + } + + /** + * @return the depth (blocks) + */ + public int getDepth() { + return depth; + } + + /** + * @param depth + * (blocks) + */ + public void setDepth(int depth) { + this.depth = depth; + } + + /** + * + * @param x + * (blocks) + * @param y + * (blocks) + * @param z + * (blocks) + */ + public void setLocation(int x, int y, int z) { + if (x != leftX || y != bottomY || z != backZ){ + invalidateCache(); + } + leftX = x; + bottomY = y; + backZ = z; + } + + /** + * + * @param x + * (blocks) + * @param y + * (blocks) + * @param z + * (blocks) + */ + public void setCenter(int x, int y, int z) { + setLocation(x - width / 2, y - height / 2, z - depth / 2); + } + + /** + * @return the left x (blocks) + */ + public int getX() { + return leftX; + } + + /** + * @return the bottom y (blocks) + */ + public int getY() { + return bottomY; + } + + /** + * @return the back z (blocks) + */ + public int getZ() { + return backZ; + } +} diff --git a/src/ru/olamedia/olacraft/world/chunk/Chunk.java b/src/ru/olamedia/olacraft/world/chunk/Chunk.java new file mode 100644 index 0000000..ca2d4bf --- /dev/null +++ b/src/ru/olamedia/olacraft/world/chunk/Chunk.java @@ -0,0 +1,290 @@ +package ru.olamedia.olacraft.world.chunk; + +import ru.olamedia.geom.SimpleQuadMesh; +import ru.olamedia.olacraft.world.blockTypes.GrassBlockType; +import ru.olamedia.olacraft.world.location.BlockLocation; +import ru.olamedia.olacraft.world.location.ChunkLocation; +import ru.olamedia.olacraft.world.provider.WorldProvider; + +public class Chunk extends BlockSlice { + public boolean isMeshCostructed = false; + public SimpleQuadMesh mesh; + + public int visibleTop = 0; + public int visibleBottom = 0; + public int visibleLeft = 0; + public int visibleRight = 0; + public int visibleFront = 0; + public int visibleBack = 0; + + public Chunk(WorldProvider provider) { + super(provider, 16, 16, 16); + } + + /** + * Convert block coordinate into chunk coordinate + * + * @param v + * block coordinate along one axis + * @return + */ + public static int v(int v) { + if (v >= 0) { + return v / 16; + } else { + return (v + 1) / 16 - 1; + } + } + + /** + * Convert block coordinate into block position inside of chunk + * + * @param v + * block coordinate along one axis + * @return + */ + public static int in(int v) { + int tmp = v - v(v) * 16; + return tmp >= 0 ? tmp : 16 + tmp; // block location minus chunk base + // location + // (lower-left-back corner) + // if (v >= 0) { + // return v % 16; + // } else { + // int in = v + 1; // shift up so -1 will be 0 + // in %= 16; // get remaining -15..0 + // in += 15; // revert 0..15 + // return in; + // } + } + + public void setMeshColor(SimpleQuadMesh mesh, int x, int y, int z, boolean isSide) { + float level = 1f;// ((float) getProvider().getBlockLightLevel(x, y, z) - + // (isSide ? 2 : 0)) / 15.0f; + mesh.setColor4f(level, level, level, 1); + if (y < 0) { + mesh.setColor4f(0, 0, 1, 1); + } else if (y > 30) { + mesh.setColor4f(1, 1, 1, 1); + } else { + mesh.setColor4f(1, 1, 0, 1); + } + } + + /** + * @return the mesh + */ + public SimpleQuadMesh getMesh() { + if (isMeshCostructed) { + return mesh; + } + if (getY() > provider.getInfo().maxHeight) { + isMeshCostructed = true; + return null; + } + if (getY() < provider.getInfo().minHeight) { + isMeshCostructed = true; + return null; + } + if (null == mesh) { + mesh = new SimpleQuadMesh(14739); // unindexed + // 17x17x17 + // vertices + mesh.useColor(); + mesh.useTexture(); + // gl.glHint(GL2.GL_PERSPECTIVE_CORRECTION_HINT, GL2.GL_FASTEST); + // gl.glHint(GL2.GL_LINE_SMOOTH_HINT, GL2.GL_NICEST); + GrassBlockType grass = new GrassBlockType(); + for (int x = getX(); x < getX() + getWidth(); x++) { + for (int y = getY(); y < getY() + getHeight(); y++) { + for (int z = getZ(); z < getZ() + getDepth(); z++) { + // + + if (!isEmptyBlock(x, y, z)) { + mesh.setTranslation(x, y, z); + // mesh.setColor4f(0, 1, 0, 1); + float cbase = (float) (y / 200.0) * (float) (7.0 / 10.0); + if (cbase > 9 / 10) { + cbase = (float) (9.0 / 10.0); + } + // cbase = (float) (9.0 / 10.0); + float cred, cgreen, cblue; + // cbase; + cred = cgreen = cblue = getLightLevel256(x, y, z); + if (x == 1) { + mesh.setColor4f(1, 0, 0, 1); + // red to the right + } + if (x == 0 || z == 0) { + if (y == 6) { + mesh.setColor4f(1, 0, 0, 1); + } else if (y % 2 == 0) { + mesh.setColor4f(1, 0, 1, 1); + } else { + mesh.setColor4f(1, 1, 0, 1); + } + } + if (z == 1) { + mesh.setColor4f(0, 0, 1, 1); + // blue to the bottom + } + if (renderBottom(x, y, z)) { + setMeshColor(mesh, x, y - 1, z, false); + mesh.setTexture(grass.getBottomTexture()); + mesh.addBottomQuad(); + visibleBottom++; + } + if (renderTop(x, y, z)) { + if (x == 15 || z == 15) { + // debug: show through.. + } else { + setMeshColor(mesh, x, y + 1, z, false); + mesh.setTexture(grass.getTopTexture()); + mesh.addTopQuad(); + } + visibleTop++; + } + if (renderLeft(x, y, z)) { + setMeshColor(mesh, x - 1, y, z, true); + mesh.setTexture(grass.getLeftTexture()); + mesh.addLeftQuad(); + visibleLeft++; + } + if (renderRight(x, y, z)) { + setMeshColor(mesh, x + 1, y, z, true); + mesh.setTexture(grass.getRightTexture()); + mesh.addRightQuad(); + visibleRight++; + } + if (renderBack(x, y, z)) { + setMeshColor(mesh, x, y, z - 1, true); + mesh.setTexture(grass.getBackTexture()); + mesh.addBackQuad(); + visibleBack++; + } + if (renderFront(x, y, z)) { + setMeshColor(mesh, x, y, z + 1, true); + mesh.setTexture(grass.getFrontTexture()); + mesh.addFrontQuad(); + visibleFront++; + } + } + } + } + } + mesh.endMesh(); + isMeshCostructed = true; + return null; + } + return mesh; + } + + /** + * @param mesh + * the mesh to set + */ + public void setMesh(SimpleQuadMesh mesh) { + this.mesh = mesh; + } + + public boolean isEmpty() { + // MUST BE LOADED + return provider.getChunk(getBlockLocation().getChunkLocation()).isEmpty(); + } + + private BlockLocation getBlockLocation() { + return new BlockLocation(getX(), getY(), getZ()); + } + + public boolean isAvailable() { + return provider.isChunkAvailable(getBlockLocation().getChunkLocation()); + } + + public boolean isNeighborsAvailable() { + int x = Chunk.v(getX()); + int y = Chunk.v(getY()); + int z = Chunk.v(getZ()); + return provider.isChunkAvailable(new ChunkLocation(x - 1, y, z)) + && provider.isChunkAvailable(new ChunkLocation(x + 1, y, z)) + && provider.isChunkAvailable(new ChunkLocation(x, y - 1, z)) + && provider.isChunkAvailable(new ChunkLocation(x, y + 1, z)) + && provider.isChunkAvailable(new ChunkLocation(x, y, z - 1)) + && provider.isChunkAvailable(new ChunkLocation(x, y, z + 1)); + } + + public void requestNeighbors() { + int x = Chunk.v(getX()); + int y = Chunk.v(getY()); + int z = Chunk.v(getZ()); + if (!provider.isChunkAvailable(new ChunkLocation(x - 1, y, z))) { + provider.loadChunk(new ChunkLocation(x - 1, y, z)); + } + if (!provider.isChunkAvailable(new ChunkLocation(x + 1, y, z))) { + provider.loadChunk(new ChunkLocation(x + 1, y, z)); + } + if (!provider.isChunkAvailable(new ChunkLocation(x, y - 1, z))) { + provider.loadChunk(new ChunkLocation(x, y - 1, z)); + } + if (!provider.isChunkAvailable(new ChunkLocation(x, y + 1, z))) { + provider.loadChunk(new ChunkLocation(x, y + 1, z)); + } + if (!provider.isChunkAvailable(new ChunkLocation(x, y, z - 1))) { + provider.loadChunk(new ChunkLocation(x, y, z - 1)); + } + if (!provider.isChunkAvailable(new ChunkLocation(x, y, z + 1))) { + provider.loadChunk(new ChunkLocation(x, y, z + 1)); + } + } + + public void request() { + BlockLocation blockLocation = new BlockLocation(getX(), getY(), getZ()); + // System.out.println("provider.requestChunk(" + + // blockLocation.getRegionLocation() + blockLocation.getChunkLocation() + // + ")"); + provider.loadChunk(blockLocation.getChunkLocation()); + } + + // public BlockType getBlockType(int x, int y, int z) { + // return provider.getBlockType(int x, int y, int z); + // } + + public boolean isEmptyBlock(int x, int y, int z) { + return provider.isEmptyBlock(x, y, z); + } + + public float getLightLevel256(int x, int y, int z) { + return ((float) getLightLevel(x, y, z)) / 15.0f;// * 255.0f + } + + public int getLightLevel(int x, int y, int z) { + return 15; + } + + public boolean renderBottom(int x, int y, int z) { + return provider.renderBottom(x, y, z); + } + + public boolean renderTop(int x, int y, int z) { + return provider.renderTop(x, y, z); + } + + public boolean renderLeft(int x, int y, int z) { + return provider.renderLeft(x, y, z); + } + + public boolean renderRight(int x, int y, int z) { + return provider.renderRight(x, y, z); + } + + public boolean renderFront(int x, int y, int z) { + return provider.renderFront(x, y, z); + } + + public boolean renderBack(int x, int y, int z) { + return provider.renderBack(x, y, z); + } + + public WorldProvider getProvider() { + return provider; + } +} diff --git a/src/ru/olamedia/olacraft/world/chunk/ChunkMeshBulder.java b/src/ru/olamedia/olacraft/world/chunk/ChunkMeshBulder.java new file mode 100644 index 0000000..d362199 --- /dev/null +++ b/src/ru/olamedia/olacraft/world/chunk/ChunkMeshBulder.java @@ -0,0 +1,47 @@ +package ru.olamedia.olacraft.world.chunk; + +import java.util.concurrent.ArrayBlockingQueue; + +public class ChunkMeshBulder extends Thread { + public static ChunkMeshBulder instance = new ChunkMeshBulder("Mesh builder"); + private ArrayBlockingQueue<Chunk> chunks = new ArrayBlockingQueue<Chunk>(16); + + public ChunkMeshBulder(String name) { + super(name); + } + + public boolean isFull() { + return chunks.remainingCapacity() == 0; + } + + public void add(Chunk chunk) { + chunks.offer(chunk); + } + + public void clear() { + chunks.clear(); + } + + public void tick() throws InterruptedException { + if (!chunks.isEmpty()) { + Chunk chunk = chunks.take(); + chunk.getMesh(); + } + } + + @Override + public void run() { + // glc.makeCurrent(); + while (true) { + // main loop + try { + tick(); + // Thread.sleep(10); // or wait/join etc + } catch (InterruptedException ex) { + // cleanup here + Thread.currentThread().interrupt(); // for nested loops + break; + } + } + } +} diff --git a/src/ru/olamedia/olacraft/world/chunk/ChunkSlice.java b/src/ru/olamedia/olacraft/world/chunk/ChunkSlice.java new file mode 100644 index 0000000..e440740 --- /dev/null +++ b/src/ru/olamedia/olacraft/world/chunk/ChunkSlice.java @@ -0,0 +1,114 @@ +package ru.olamedia.olacraft.world.chunk; + +import java.util.HashMap; + +import ru.olamedia.olacraft.world.provider.WorldProvider; + +public class ChunkSlice { + private WorldProvider provider; + private int leftX; + private int bottomY; + private int backZ; + private int width; + private int height; + private int depth; + + public ChunkSlice(WorldProvider provider, int width, int height, int depth) { + this.provider = provider; + this.width = width; + this.height = height; + this.depth = depth; + } + + protected HashMap<String, Chunk> chunks = new HashMap<String, Chunk>(); + + public Chunk getChunk(int x, int y, int z) { + String key = x + ";" + y + ";" + z; + if (chunks.containsKey(key)) { + return chunks.get(key); + } else { + Chunk chunk = new Chunk(provider); + chunk.setLocation(x * 16, y * 16, z * 16); + chunks.put(key, chunk); + return chunk; + } + } + + /** + * @return the width + */ + public int getWidth() { + return width; + } + + /** + * @param width + * the width to set + */ + public void setWidth(int width) { + this.width = width; + } + + /** + * @return the height + */ + public int getHeight() { + return height; + } + + /** + * @param height + * the height to set + */ + public void setHeight(int height) { + this.height = height; + } + + /** + * @return the depth + */ + public int getDepth() { + return depth; + } + + /** + * @param depth + * the depth to set + */ + public void setDepth(int depth) { + this.depth = depth; + } + + public void setLocation(int x, int y, int z) { + leftX = x; + bottomY = y; + backZ = z; + } + + public void setCenter(int x, int y, int z) { + leftX = x - width / 2; + bottomY = y - height / 2; + backZ = z - depth / 2; + } + + /** + * @return the leftX + */ + public int getX() { + return leftX; + } + + /** + * @return the bottomY + */ + public int getY() { + return bottomY; + } + + /** + * @return the backZ + */ + public int getZ() { + return backZ; + } +} diff --git a/src/ru/olamedia/olacraft/world/chunk/package-info.java b/src/ru/olamedia/olacraft/world/chunk/package-info.java new file mode 100644 index 0000000..314ea35 --- /dev/null +++ b/src/ru/olamedia/olacraft/world/chunk/package-info.java @@ -0,0 +1,8 @@ +/** + * + */ +/** + * @author olamedia + * + */ +package ru.olamedia.olacraft.world.chunk;
\ No newline at end of file diff --git a/src/ru/olamedia/olacraft/world/data/ChunkData.java b/src/ru/olamedia/olacraft/world/data/ChunkData.java new file mode 100644 index 0000000..a1abc9e --- /dev/null +++ b/src/ru/olamedia/olacraft/world/data/ChunkData.java @@ -0,0 +1,86 @@ +package ru.olamedia.olacraft.world.data; + +import java.io.Serializable; +import java.util.BitSet; + +import ru.olamedia.olacraft.world.chunk.Chunk; +import ru.olamedia.olacraft.world.location.BlockLocation; +import ru.olamedia.olacraft.world.location.ChunkLocation; + +public class ChunkData implements Serializable { + private static final long serialVersionUID = -5704237444737895501L; + public ChunkLocation location; + public static transient int SIZE = 4096; + // private boolean[] notEmpty = new boolean[SIZE]; + private BitSet emptyBlocks = new BitSet(4096); + public int notEmptyCount = 0; + + // public transient int[] type = new int[SIZE]; + // /public transient ChunkLightData light; + + public ChunkData() { + // light = new ChunkLightData(); + } + + public void compact() { + if (notEmptyCount == 0) { + emptyBlocks = null; + } + } + + public static int normalize(int v) { + int n = v; + if (n > 15) { + n = n % 16; + } + if (n < 0) { + n = 16 + n % 16 - 1; + // v = 15 - v; + } + // System.out.println("normalize(" + v + ") = " + n); + return n; + } + + public static int getId(int xInsideChunk, int yInsideChunk, int zInsideChunk) { + xInsideChunk = normalize(xInsideChunk); + yInsideChunk = normalize(yInsideChunk); + zInsideChunk = normalize(zInsideChunk); + int id = xInsideChunk * 16 * 16 + yInsideChunk * 16 + zInsideChunk; + if (id > SIZE) { + System.err.println("Exception while getID(" + xInsideChunk + "," + yInsideChunk + "," + zInsideChunk + ")"); + throw new ArrayIndexOutOfBoundsException(id); + } + return id; + } + + public boolean isEmpty(BlockLocation blockLocation) { + if (notEmptyCount == 0) { + return true; + } + int id = getId(Chunk.in(blockLocation.x), Chunk.in(blockLocation.y), Chunk.in(blockLocation.z)); + return isEmpty(id); + // return !notEmpty[id]; + } + + public boolean isEmpty(int id) { + if (notEmptyCount == 0) { + return true; + } + return emptyBlocks.get(id); + } + + public void setEmpty(int id, boolean isEmpty) { + if (isEmpty(id) != isEmpty) { + if (!isEmpty) { + notEmptyCount++; + } else { + notEmptyCount--; + } + } + emptyBlocks.set(id, isEmpty); + } + + public boolean isEmpty() { + return notEmptyCount == 0; + } +} diff --git a/src/ru/olamedia/olacraft/world/data/ChunkLightData.java b/src/ru/olamedia/olacraft/world/data/ChunkLightData.java new file mode 100644 index 0000000..f574420 --- /dev/null +++ b/src/ru/olamedia/olacraft/world/data/ChunkLightData.java @@ -0,0 +1,102 @@ +package ru.olamedia.olacraft.world.data; + +import ru.olamedia.olacraft.world.dataProvider.AbstractChunkDataProvider; + +/** + * The daylight calculated as sum of sunlight + emitted light + * The nightlight calculated as sum of emitted light + * + * The light at some time of a day calculated as part of daylight + part of + * nightlight (ex 30% of night + 70% of daylight) - sum of two array's elements + */ +public class ChunkLightData { + public static int SIZE = 4096; + /** + * Constant sunlight level + */ + public byte[] sunLevel = new byte[SIZE]; + /** + * Constant sunlight level + */ + public byte[] emittedLevel = new byte[SIZE]; + /** + * Constant light level during middle of a day + */ + public byte[] daytimeLevel = new byte[SIZE]; + /** + * Constant light level during midnight + */ + public byte[] nighttimeLevel = new byte[SIZE]; + public boolean isCalculated = false; + public boolean isSunlevelCalculated = false; + public byte[] level = new byte[SIZE]; + + public static int normalize(int v) { + int n = v; + if (n > 15) { + n = n % 16; + } + if (n < 0) { + n = 16 + n % 16 - 1; + // v = 15 - v; + } + // System.out.println("normalize(" + v + ") = " + n); + return n; + } + + public static int getId(int xInsideChunk, int yInsideChunk, int zInsideChunk) { + xInsideChunk = normalize(xInsideChunk); + yInsideChunk = normalize(yInsideChunk); + zInsideChunk = normalize(zInsideChunk); + int id = xInsideChunk * 16 * 16 + yInsideChunk * 16 + zInsideChunk; + if (id > SIZE) { + System.err.println("Exception while getID(" + xInsideChunk + "," + yInsideChunk + "," + zInsideChunk + ")"); + throw new ArrayIndexOutOfBoundsException(id); + } + return id; + } + + private static byte sunlight = 15; + + public void fillSunlight() { + // simplify: straight from top to bottom, utility to fill top layer + for (int x = 0; x < 16; x++) { + for (int z = 0; z < 16; z++) { + sunLevel[getId(x, 15, z)] = sunlight; + } + } + } + + public void copySunlightFromAbove(ChunkLightData above) { + for (int x = 0; x < 16; x++) { + for (int z = 0; z < 16; z++) { + sunLevel[getId(x, 15, z)] = above.sunLevel[getId(x, 0, z)]; + } + } + System.out.print("Copy sunlight"); + } + + /** + * Sunlight falling down until meets nonempty block from data + * + * @param data + */ + public void falldownSunlight(ChunkData data) { + for (int x = 0; x < 16; x++) { + for (int z = 0; z < 16; z++) { + for (int y = 14; y >= 0; y--) { + if (!data.isEmpty(getId(x, y, z))) { + break; + } else { + sunLevel[getId(x, y, z)] = sunLevel[getId(x, y + 1, z)]; + } + } + } + } + } + + public void receiveNeighborLight(AbstractChunkDataProvider abstractChunkDataProvider) { + + } + +} diff --git a/src/ru/olamedia/olacraft/world/data/HeightMap.java b/src/ru/olamedia/olacraft/world/data/HeightMap.java new file mode 100644 index 0000000..b2c0a63 --- /dev/null +++ b/src/ru/olamedia/olacraft/world/data/HeightMap.java @@ -0,0 +1,42 @@ +package ru.olamedia.olacraft.world.data; + +import java.io.Serializable; + +/** + * Heightmap + * Useful when looking for spawn location, calculating light + * + * @author olamedia + * + */ +public class HeightMap implements Serializable { + private static final long serialVersionUID = -6777972159522169977L; + public byte[][] map; // -128..127 + public HeightMap(){ + + } + public HeightMap(int width, int height) { + map = new byte[width][height]; + } + + public void setHeight(int x, int y, int height) { + map[x][y] = (byte) height; + } + + public int getHeight(int x, int y) { + return map[x][y]; + } + + @Override + public String toString() { + StringBuilder b = new StringBuilder(); + for (int x = 0; x < map.length; x++){ + for (int z = 0; z < map[x].length; z++){ + b.append(map[x][z]); + b.append(","); + } + b.append("\n"); + } + return b.toString(); + } +} diff --git a/src/ru/olamedia/olacraft/world/data/RegionData.java b/src/ru/olamedia/olacraft/world/data/RegionData.java new file mode 100644 index 0000000..fa292d2 --- /dev/null +++ b/src/ru/olamedia/olacraft/world/data/RegionData.java @@ -0,0 +1,57 @@ +package ru.olamedia.olacraft.world.data; + +import java.io.IOException; +import java.io.InputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.OutputStream; +import java.io.Serializable; + +import ru.olamedia.olacraft.world.chunk.Chunk; +import ru.olamedia.olacraft.world.location.ChunkLocation; +import ru.olamedia.olacraft.world.location.RegionLocation; +import ru.olamedia.olacraft.world.location.SectorLocation; + +/** + * Region is a 16x16 range of sectors. (256x256x256 blocks) + * + * @author olamedia + * + */ +public class RegionData implements Serializable { + private static final long serialVersionUID = 7449677895073874520L; + public RegionLocation location; + public HeightMap heightMap = new HeightMap(256, 256); + public SectorData[][] sectorData = new SectorData[16][16]; + + public void writeTo(OutputStream stream) throws IOException { + ObjectOutputStream out = new ObjectOutputStream(stream); + out.writeObject(this); + out.close(); + } + + public static RegionData loadFrom(InputStream stream) throws IOException, ClassNotFoundException { + ObjectInputStream in = new ObjectInputStream(stream); + RegionData data = (RegionData) in.readObject(); + in.close(); + return data; + } + + public static RegionData createEmpty(RegionLocation location) { + RegionData data = new RegionData(); + data.location = location; + return data; + } + + public ChunkData getChunkData(ChunkLocation chunkLocation) { + SectorData sector = getSectorData(chunkLocation.getSectorLocation()); + int y = Chunk.in(chunkLocation.y + 128); // minHeight = -128 + return sector.chunkData[y]; + } + + public SectorData getSectorData(SectorLocation sectorLocation) { + int x = Chunk.in(sectorLocation.x); + int z = Chunk.in(sectorLocation.z); + return sectorData[x][z]; + } +} diff --git a/src/ru/olamedia/olacraft/world/data/SectorData.java b/src/ru/olamedia/olacraft/world/data/SectorData.java new file mode 100644 index 0000000..12a97cd --- /dev/null +++ b/src/ru/olamedia/olacraft/world/data/SectorData.java @@ -0,0 +1,33 @@ +package ru.olamedia.olacraft.world.data; + +import java.io.Serializable; + +import ru.olamedia.olacraft.world.location.SectorLocation; + +/** + * Sector: set of all chunks by one x,z vertical + * + * @author olamedia + * + */ +public class SectorData implements Serializable{ + private static final long serialVersionUID = 5304471397211814748L; + public HeightMap heightMap; // locations of highest nonempty blocks + public ChunkData[] chunkData; // 256/16 = 16 + public SectorLocation location; + + public static int yIndex(int y) { + return (y + 128) / 16; + // 1: (-128 + 128) / 16 = 0 + // ...... + // 15: (-114 + 128) / 16 = 14/16 = 0 + // 16: (-113 + 128) / 16 = 15/16 = 0 + // 17: (-112 + 128) / 16 = 16/16 = 1 + } + public static SectorData generate(){ + SectorData data = new SectorData(); + data.heightMap = new HeightMap(16, 16); + data.chunkData = new ChunkData[16]; + return data; + } +} diff --git a/src/ru/olamedia/olacraft/world/data/UnavailableDataException.java b/src/ru/olamedia/olacraft/world/data/UnavailableDataException.java new file mode 100644 index 0000000..a75a42e --- /dev/null +++ b/src/ru/olamedia/olacraft/world/data/UnavailableDataException.java @@ -0,0 +1,23 @@ +package ru.olamedia.olacraft.world.data; + +public class UnavailableDataException extends Exception { + + public UnavailableDataException() { + super(); + } + + public UnavailableDataException(String message, Throwable cause) { + super(message, cause); + } + + public UnavailableDataException(String message) { + super(message); + } + + public UnavailableDataException(Throwable cause) { + super(cause); + } + + private static final long serialVersionUID = -8955947061088863309L; + +} diff --git a/src/ru/olamedia/olacraft/world/data/package-info.java b/src/ru/olamedia/olacraft/world/data/package-info.java new file mode 100644 index 0000000..2a171a6 --- /dev/null +++ b/src/ru/olamedia/olacraft/world/data/package-info.java @@ -0,0 +1,8 @@ +/** + * + */ +/** + * @author olamedia + * + */ +package ru.olamedia.olacraft.world.data;
\ No newline at end of file diff --git a/src/ru/olamedia/olacraft/world/dataProvider/AbstractChunkDataProvider.java b/src/ru/olamedia/olacraft/world/dataProvider/AbstractChunkDataProvider.java new file mode 100644 index 0000000..1670ef3 --- /dev/null +++ b/src/ru/olamedia/olacraft/world/dataProvider/AbstractChunkDataProvider.java @@ -0,0 +1,60 @@ +package ru.olamedia.olacraft.world.dataProvider; + +import ru.olamedia.olacraft.world.data.ChunkData; +import ru.olamedia.olacraft.world.data.RegionData; +import ru.olamedia.olacraft.world.data.SectorData; +import ru.olamedia.olacraft.world.location.ChunkLocation; +import ru.olamedia.olacraft.world.location.RegionLocation; +import ru.olamedia.olacraft.world.location.SectorLocation; + +abstract public class AbstractChunkDataProvider { + /** + * is data already available or we should wait + * + * @param RegionLocation + * @return + */ + public boolean isChunkAvailable(ChunkLocation chunkLocation) { + return this.isRegionAvailable(chunkLocation.getRegionLocation()); + } + + public boolean isSectorAvailable(SectorLocation sectorLocation) { + return this.isRegionAvailable(sectorLocation.getRegionLocation()); + } + + abstract public boolean isRegionAvailable(RegionLocation regionLocation); + + /** + * we need this chunk now, send request to server or preload + * + * @param RegionLocation + */ + public void loadChunk(ChunkLocation chunkLocation) { + //System.out.println("loadChunk(" + chunkLocation + ")"); + this.loadRegion(chunkLocation.getRegionLocation()); + //System.out.println("loadChunk(" + chunkLocation + ")--"); + } + + public void loadSector(SectorLocation sectorLocation) { + this.loadRegion(sectorLocation.getRegionLocation()); + } + + abstract public void loadRegion(RegionLocation regionLocation); + + /** + * Get data if already available + * + * @param RegionLocation + * @return + */ + public ChunkData getChunk(ChunkLocation chunkLocation) { + return this.getRegion(chunkLocation.getRegionLocation()).getChunkData(chunkLocation); + } + + public SectorData getSector(SectorLocation sectorLocation) { + return this.getRegion(sectorLocation.getRegionLocation()).getSectorData(sectorLocation); + } + + abstract public RegionData getRegion(RegionLocation regionLocation); + +} diff --git a/src/ru/olamedia/olacraft/world/dataProvider/CachedChunkDataProvider.java b/src/ru/olamedia/olacraft/world/dataProvider/CachedChunkDataProvider.java new file mode 100644 index 0000000..23270a7 --- /dev/null +++ b/src/ru/olamedia/olacraft/world/dataProvider/CachedChunkDataProvider.java @@ -0,0 +1,70 @@ +package ru.olamedia.olacraft.world.dataProvider; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +import ru.olamedia.olacraft.world.data.RegionData; +import ru.olamedia.olacraft.world.location.RegionLocation; + +public class CachedChunkDataProvider extends AbstractChunkDataProvider { + private AbstractChunkDataProvider provider; + private HashMap<String, RegionData> regionMap = new HashMap<String, RegionData>(); + private List<String> loading = new ArrayList<String>(); + + public CachedChunkDataProvider(AbstractChunkDataProvider provider) { + this.provider = provider; + } + + private static boolean DEBUG = true; + + private void debug(String s) { + if (DEBUG) { + System.out.println("[CachedChunkDataProvider] " + s); + } + } + + @Override + public boolean isRegionAvailable(RegionLocation regionLocation) { + String key = regionLocation.toString();// regionLocation.x + "-" + + // regionLocation.z; + if (regionMap.containsKey(key)) { + return true; + } + if (loading.contains(key)) { + // return false; + } + return provider.isRegionAvailable(regionLocation); + } + + @Override + public void loadRegion(RegionLocation regionLocation) { + String key = regionLocation.toString(); + //debug("loadRegion(" + regionLocation + ")"); + if (!regionMap.containsKey(key)) { + if (!loading.contains(key)) { + debug("load()"); + loading.add(key); + provider.loadRegion(regionLocation); + }else{ + //debug("loadRegion(" + regionLocation + ") already in loading"); + } + }else{ + debug("error: loadRegion(" + regionLocation + ") already in regionMap"); + } + } + + @Override + public RegionData getRegion(RegionLocation regionLocation) { + String key = regionLocation.toString(); + if (regionMap.containsKey(key)) { + return regionMap.get(key); + } else { + RegionData data = provider.getRegion(regionLocation); + regionMap.put(key, data); + loading.remove(key); + return data; + } + } + +} diff --git a/src/ru/olamedia/olacraft/world/dataProvider/LocalChunkDataProvider.java b/src/ru/olamedia/olacraft/world/dataProvider/LocalChunkDataProvider.java new file mode 100644 index 0000000..514081f --- /dev/null +++ b/src/ru/olamedia/olacraft/world/dataProvider/LocalChunkDataProvider.java @@ -0,0 +1,218 @@ +package ru.olamedia.olacraft.world.dataProvider; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +import ru.olamedia.olacraft.world.data.ChunkData; +import ru.olamedia.olacraft.world.data.RegionData; +import ru.olamedia.olacraft.world.generator.HeightMapGenerator; +import ru.olamedia.olacraft.world.generator.RegionGenerator; +import ru.olamedia.olacraft.world.location.RegionLocation; + +public class LocalChunkDataProvider extends AbstractChunkDataProvider { + private String worldName; + private String path; + + private static boolean DEBUG = true; + + private void debug(String s) { + if (DEBUG) { + System.out.println("[LocalChunkDataProvider] " + s); + } + } + + public LocalChunkDataProvider(String worldName) { + this.worldName = worldName; + path = "data" + File.separator + this.worldName; + File worldDir = new File(path); + if (!worldDir.isDirectory()) { + worldDir.mkdirs(); + } + } + + private int[] seed; + + private int[] getSeed() throws IOException { + if (null == seed) { + String filename = path + File.separator + "world.seed"; + File seedFile = new File(filename); + // md5 - 32x0-f = 16 bytes or 8 short int + seed = new int[8]; + if (seedFile.exists()) { + InputStream in = null; + DataInputStream din = null; + in = new FileInputStream(seedFile); + din = new DataInputStream(in); + for (int i = 0; i < 8; i++) { + seed[i] = din.readShort(); + } + din.close(); + in.close(); + } else { + OutputStream out = new FileOutputStream(seedFile); + DataOutputStream dout = new DataOutputStream(out); + for (int i = 0; i < 8; i++) { + seed[i] = (int) (Integer.MAX_VALUE * Math.random()); + dout.writeShort(seed[i]); + } + dout.close(); + out.close(); + } + } + return seed; + } + + @Override + public boolean isRegionAvailable(RegionLocation regionLocation) { + return true; + } + + @Override + public void loadRegion(RegionLocation regionLocation) { + // do nothing... + debug("loadRegion(" + regionLocation + ")"); + } + + private ChunkData createChunk(int chunkX, int chunkY, int chunkZ) { + debug("createChunk " + chunkX + " " + chunkY + " " + chunkZ); + ChunkData data = new ChunkData(); + try { + getSeed(); + } catch (IOException e) { + e.printStackTrace(); + } + HeightMapGenerator.minValue = 1; + HeightMapGenerator.maxValue = 64; + HeightMapGenerator.init(); + HeightMapGenerator.seed = seed[0]; + int[][] heightMap = HeightMapGenerator.getChunkHeightMap(chunkX, chunkZ); + for (int y = 0; y < 16; y++) { + for (int x = 0; x < 16; x++) { + for (int z = 0; z < 16; z++) { + data.setEmpty(ChunkData.getId(x, y, z), (heightMap[x][z] < chunkY * 16 + y)); + } + } + } + return data; + } + + @Override + public RegionData getRegion(RegionLocation regionLocation) { + String filename = path + File.separator + regionLocation.getFilename(); + RegionData data = null; + // TODO READ/WRITE FILE + File chunkFile = new File(filename); + if (chunkFile.exists()) { + InputStream in; + try { + in = new FileInputStream(chunkFile); + data = RegionData.loadFrom(in); + in.close(); + } catch (FileNotFoundException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } catch (ClassNotFoundException e) { + e.printStackTrace(); + } + } else { + data = generateRegion(regionLocation); + try { + chunkFile.createNewFile(); + FileOutputStream out = new FileOutputStream(chunkFile); + data.writeTo(out); + out.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + return data; + } + + public RegionData generateRegion(RegionLocation regionLocation) { + RegionData data = new RegionData(); + data.location = regionLocation; + // TODO FILL HERE + RegionGenerator generator = new RegionGenerator(); + try { + generator.setSeed(getSeed()); + } catch (IOException e) { + e.printStackTrace(); + } + generator.generate(data); + return data; + } + + public ChunkData get(int chunkX, int chunkY, int chunkZ) { + debug("get " + chunkX + " " + chunkY + " " + chunkZ); + ChunkData data = null; + String filename = path + File.separator + chunkX + "_" + chunkY + "_" + chunkZ + ".chunk"; + /* + * File chunkFile = new File(filename); + * if (chunkFile.exists()) { + * try { + * InputStream in = new FileInputStream(chunkFile); + * DataInputStream din = new DataInputStream(in); + * data = new ChunkData(); + * data.readFrom(din); + * din.close(); + * in.close(); + * } catch (FileNotFoundException e) { + * e.printStackTrace(); + * } catch (IOException e) { + * e.printStackTrace(); + * } + * } else { + */ + data = createChunk(chunkX, chunkY, chunkZ); + /* + * OutputStream out = null; + * ByteArrayOutputStream bout = null; + * DataOutputStream dout = null; + * try { + * chunkFile.createNewFile(); + * out = new FileOutputStream(chunkFile); + * // bout = new ByteArrayOutputStream(4096); + * dout = new DataOutputStream(out); + * data.writeTo(dout); + * // dout.flush(); + * // out.write(bout.toByteArray()); + * out.flush(); + * } catch (IOException e) { + * e.printStackTrace(); + * } finally { + * if (null != dout) { + * try { + * dout.close(); + * } catch (IOException e) { + * e.printStackTrace(); + * } + * } + * if (null != bout) { + * try { + * bout.close(); + * } catch (IOException e) { + * e.printStackTrace(); + * } + * } + * if (null != out) { + * try { + * out.close(); + * } catch (IOException e) { + * e.printStackTrace(); + * } + * } + * } + * } + */ + return data; + } + +} diff --git a/src/ru/olamedia/olacraft/world/dataProvider/LocalRegionDataProvider.java b/src/ru/olamedia/olacraft/world/dataProvider/LocalRegionDataProvider.java new file mode 100644 index 0000000..447bcc3 --- /dev/null +++ b/src/ru/olamedia/olacraft/world/dataProvider/LocalRegionDataProvider.java @@ -0,0 +1,57 @@ +package ru.olamedia.olacraft.world.dataProvider; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +public class LocalRegionDataProvider { + private String worldName; + private String path; + + public LocalRegionDataProvider(String worldName) { + this.worldName = worldName; + path = "data" + File.separator + this.worldName; + File worldDir = new File(path); + if (!worldDir.isDirectory()) { + worldDir.mkdirs(); + } + } + + private int[] seed; + + private int[] getSeed() throws IOException { + if (null == seed) { + String filename = path + File.separator + "world.seed"; + File seedFile = new File(filename); + // md5 - 32x0-f = 16 bytes or 8 short int + seed = new int[8]; + if (seedFile.exists()) { + InputStream in = null; + DataInputStream din = null; + in = new FileInputStream(seedFile); + din = new DataInputStream(in); + for (int i = 0; i < 8; i++) { + seed[i] = din.readShort(); + } + din.close(); + in.close(); + } else { + OutputStream out = new FileOutputStream(seedFile); + DataOutputStream dout = new DataOutputStream(out); + for (int i = 0; i < 8; i++) { + seed[i] = (int) (Integer.MAX_VALUE * Math.random()); + dout.writeShort(seed[i]); + } + dout.close(); + out.close(); + } + } + return seed; + } + +} diff --git a/src/ru/olamedia/olacraft/world/dataProvider/RemoteChunkDataProvider.java b/src/ru/olamedia/olacraft/world/dataProvider/RemoteChunkDataProvider.java new file mode 100644 index 0000000..8284ff9 --- /dev/null +++ b/src/ru/olamedia/olacraft/world/dataProvider/RemoteChunkDataProvider.java @@ -0,0 +1,75 @@ +package ru.olamedia.olacraft.world.dataProvider; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +import com.esotericsoftware.kryonet.Connection; + +import ru.olamedia.olacraft.network.GameClient; +import ru.olamedia.olacraft.network.packet.GetRegionPacket; +import ru.olamedia.olacraft.network.packet.IPacket; +import ru.olamedia.olacraft.network.packet.IPacketListener; +import ru.olamedia.olacraft.network.packet.RegionDataPacket; +import ru.olamedia.olacraft.world.data.RegionData; +import ru.olamedia.olacraft.world.location.RegionLocation; + +public class RemoteChunkDataProvider extends AbstractChunkDataProvider implements IPacketListener { + + private GameClient client; + private HashMap<String, RegionData> map = new HashMap<String, RegionData>(); + private List<String> loading = new ArrayList<String>(); + + public RemoteChunkDataProvider(GameClient client) { + this.client = client; + this.client.addPacketListener(this); + } + + private static boolean DEBUG = true; + + private void debug(String s) { + if (DEBUG) { + System.out.println("[RemoteChunkDataProvider] " + s); + } + } + + @Override + public void loadRegion(RegionLocation regionLocation) { + String key = regionLocation.toString(); + debug("loadRegion(" + key + ")"); + if (!loading.contains(key)) { + loading.add(key); + client.send(new GetRegionPacket(regionLocation)); + debug("sent packet: GetRegionPacket"); + } + } + + @Override + public boolean isRegionAvailable(RegionLocation regionLocation) { + String key = regionLocation.toString(); + if (loading.contains(key)) { + return false; + } + return map.containsKey(key); + } + + @Override + public RegionData getRegion(RegionLocation regionLocation) { + String key = regionLocation.toString(); + RegionData data = map.get(key); + map.remove(key); + return data; + } + + @Override + public void onPacket(Connection connection, IPacket p) { + if (p instanceof RegionDataPacket) { + debug("received packet [conn " + connection.getID() + "]: ChunkDataPacket"); + RegionData data = ((RegionDataPacket) p).data; + String key = data.location.toString(); + map.put(key, data); + loading.remove(key); + } + } + +} diff --git a/src/ru/olamedia/olacraft/world/dataProvider/package-info.java b/src/ru/olamedia/olacraft/world/dataProvider/package-info.java new file mode 100644 index 0000000..6a411e6 --- /dev/null +++ b/src/ru/olamedia/olacraft/world/dataProvider/package-info.java @@ -0,0 +1,8 @@ +/** + * + */ +/** + * @author olamedia + * + */ +package ru.olamedia.olacraft.world.dataProvider;
\ No newline at end of file diff --git a/src/ru/olamedia/olacraft/world/generator/HeightMapGenerator.java b/src/ru/olamedia/olacraft/world/generator/HeightMapGenerator.java new file mode 100644 index 0000000..c3e32b5 --- /dev/null +++ b/src/ru/olamedia/olacraft/world/generator/HeightMapGenerator.java @@ -0,0 +1,157 @@ +package ru.olamedia.olacraft.world.generator; + +import ru.olamedia.olacraft.world.chunk.Chunk; +import ru.olamedia.olacraft.world.data.HeightMap; +import ru.olamedia.olacraft.world.location.RegionLocation; +import libnoiseforjava.NoiseGen.NoiseQuality; +import libnoiseforjava.exception.ExceptionInvalidParam; +import libnoiseforjava.module.Billow; +import libnoiseforjava.module.Blend; +import libnoiseforjava.module.Max; +import libnoiseforjava.module.Perlin; +import libnoiseforjava.module.RidgedMulti; +import libnoiseforjava.module.ScaleBias; +import libnoiseforjava.module.Select; +import libnoiseforjava.module.Turbulence; +import libnoiseforjava.util.NoiseMap; +import libnoiseforjava.util.NoiseMapBuilderPlane; + +public class HeightMapGenerator { + public static int minValue; + public static int maxValue; + + public static int seed = (int) (Integer.MAX_VALUE * Math.random()); + + private static Billow plainsNoise; + private static ScaleBias plains; + private static RidgedMulti hillsNoise; + private static ScaleBias hills; + private static RidgedMulti mountainsNoise; + private static ScaleBias mountains; + private static Perlin terrainType; + private static Blend blendedTerrain; + private static Select selectedTerrain; + private static Max maxTerrain; + private static Turbulence turbulence; + private static ScaleBias finalTerrain; + + private static boolean isInitialized = false; + + public static void init() { + if (isInitialized) { + return; + } + isInitialized = true; + try { + // PLAINS + plainsNoise = new Billow(); + plainsNoise.setFrequency(0.01); + plains = new ScaleBias(plainsNoise); + plains.setScale(0.05); + plains.setBias(-0.75); + // HILLS + hillsNoise = new RidgedMulti(); + hillsNoise.setFrequency(0.01); + hills = new ScaleBias(hillsNoise); + hills.setScale(0.5); + hills.setBias(-0.75); + // MOUNTAINS + mountainsNoise = new RidgedMulti(); + mountainsNoise.setFrequency(0.04); + mountainsNoise.setOctaveCount(6); + turbulence = new Turbulence(mountainsNoise); + turbulence.setFrequency(0.2); + turbulence.setPower(1); + mountains = new ScaleBias(turbulence); + mountains.setScale(1.0); + mountains.setBias(-1.25); + terrainType = new Perlin(); + terrainType.setOctaveCount(6); + terrainType.setFrequency(0.06); + terrainType.setPersistence(0.25); + terrainType.setNoiseQuality(NoiseQuality.QUALITY_BEST); + selectedTerrain = new Select(plains, mountains, terrainType); + selectedTerrain.setBounds(0, 1); + selectedTerrain.setEdgeFalloff(0.125); + blendedTerrain = new Blend(plains, mountains, terrainType); + maxTerrain = new Max(plains, turbulence); + finalTerrain = new ScaleBias(maxTerrain); + finalTerrain.setBias(2); + setSeed(seed); + } catch (ExceptionInvalidParam e) { + e.printStackTrace(); + } + } + + public static void setSeed(int newseed) { + seed = newseed; + plainsNoise.setSeed(seed); + hillsNoise.setSeed(seed); + mountainsNoise.setSeed(seed); + terrainType.setSeed(seed); + } + + public static int[][] getChunkHeightMap(int chunkX, int chunkZ) { + init(); + try { + NoiseMapBuilderPlane builder = new NoiseMapBuilderPlane(16, 16); + // builder.enableSeamless(true); + // Perlin plains = new Perlin(); + + // Select finalTerrain = new Select(plains, mountains, null); + // finalTerrain.setControlModule(terrainType); + // finalTerrain.setBounds(0.0, 1000); + // finalTerrain.setEdgeFalloff(1.25); + + NoiseMap heightMap = new NoiseMap(16, 16); + builder.setSourceModule(maxTerrain); + builder.setDestNoiseMap(heightMap); + double bx = chunkX; + double bz = chunkZ; + builder.setDestSize(16, 16); + builder.setBounds(bx, bx + 1, bz, bz + 1); + builder.build(); + double[][] heights = heightMap.getNoiseMap(); + int[][] ints = new int[16][16]; + // System.out.print("heightmap:"); + for (int x = 0; x < 16; x++) { + for (int z = 0; z < 16; z++) { + // System.out.print(((float) heights[x][z]) + ";"); + ints[x][z] = (int) (minValue + (maxValue - minValue) * (heights[x][z] + 1) / 2); + } + } + // System.out.println(""); + return ints; + } catch (ExceptionInvalidParam e) { + e.printStackTrace(); + } + return null; + } + + public static HeightMap getHeightMap(RegionLocation location) { + init(); + HeightMap map = new HeightMap(256, 256); + try { + NoiseMapBuilderPlane builder = new NoiseMapBuilderPlane(256, 256); + NoiseMap heightMap = new NoiseMap(256, 256); + builder.setSourceModule(finalTerrain); + builder.setDestNoiseMap(heightMap); + builder.setDestSize(256, 256); + float bx = location.x; + float bz = location.z; + builder.setBounds(bx, bx + 1, bz, bz + 1); + builder.build(); + double[][] heights = heightMap.getNoiseMap(); + for (int x = 0; x < 256; x++) { + for (int z = 0; z < 256; z++) { + map.setHeight(x, z, 0); + //(int) (minValue + (maxValue - minValue) * (heights[x][z] + 1) / 2) + } + } + return map; + } catch (ExceptionInvalidParam e) { + e.printStackTrace(); + } + return null; + } +} diff --git a/src/ru/olamedia/olacraft/world/generator/ImprovedNoise.java b/src/ru/olamedia/olacraft/world/generator/ImprovedNoise.java new file mode 100644 index 0000000..365aa12 --- /dev/null +++ b/src/ru/olamedia/olacraft/world/generator/ImprovedNoise.java @@ -0,0 +1,61 @@ +package ru.olamedia.olacraft.world.generator; + +//JAVA REFERENCE IMPLEMENTATION OF IMPROVED NOISE - COPYRIGHT 2002 KEN PERLIN. + +public final class ImprovedNoise { + static public double noise(double x, double y, double z) { + int X = (int) Math.floor(x) & 255, // FIND UNIT CUBE THAT + Y = (int) Math.floor(y) & 255, // CONTAINS POINT. + Z = (int) Math.floor(z) & 255; + x -= Math.floor(x); // FIND RELATIVE X,Y,Z + y -= Math.floor(y); // OF POINT IN CUBE. + z -= Math.floor(z); + double u = fade(x), // COMPUTE FADE CURVES + v = fade(y), // FOR EACH OF X,Y,Z. + w = fade(z); + int A = p[X] + Y, AA = p[A] + Z, AB = p[A + 1] + Z, // HASH COORDINATES + // OF + B = p[X + 1] + Y, BA = p[B] + Z, BB = p[B + 1] + Z; // THE 8 CUBE + // CORNERS, + + return lerp(w, lerp(v, lerp(u, grad(p[AA], x, y, z), // AND ADD + grad(p[BA], x - 1, y, z)), // BLENDED + lerp(u, grad(p[AB], x, y - 1, z), // RESULTS + grad(p[BB], x - 1, y - 1, z))),// FROM 8 + lerp(v, lerp(u, grad(p[AA + 1], x, y, z - 1), // CORNERS + grad(p[BA + 1], x - 1, y, z - 1)), // OF CUBE + lerp(u, grad(p[AB + 1], x, y - 1, z - 1), grad(p[BB + 1], x - 1, y - 1, z - 1)))); + } + + static double fade(double t) { + return t * t * t * (t * (t * 6 - 15) + 10); + } + + static double lerp(double t, double a, double b) { + return a + t * (b - a); + } + + static double grad(int hash, double x, double y, double z) { + int h = hash & 15; // CONVERT LO 4 BITS OF HASH CODE + double u = h < 8 ? x : y, // INTO 12 GRADIENT DIRECTIONS. + v = h < 4 ? y : h == 12 || h == 14 ? x : z; + return ((h & 1) == 0 ? u : -u) + ((h & 2) == 0 ? v : -v); + } + + static final int p[] = new int[512], permutation[] = { 151, 160, 137, 91, 90, 15, 131, 13, 201, 95, 96, 53, 194, + 233, 7, 225, 140, 36, 103, 30, 69, 142, 8, 99, 37, 240, 21, 10, 23, 190, 6, 148, 247, 120, 234, 75, 0, 26, + 197, 62, 94, 252, 219, 203, 117, 35, 11, 32, 57, 177, 33, 88, 237, 149, 56, 87, 174, 20, 125, 136, 171, + 168, 68, 175, 74, 165, 71, 134, 139, 48, 27, 166, 77, 146, 158, 231, 83, 111, 229, 122, 60, 211, 133, 230, + 220, 105, 92, 41, 55, 46, 245, 40, 244, 102, 143, 54, 65, 25, 63, 161, 1, 216, 80, 73, 209, 76, 132, 187, + 208, 89, 18, 169, 200, 196, 135, 130, 116, 188, 159, 86, 164, 100, 109, 198, 173, 186, 3, 64, 52, 217, 226, + 250, 124, 123, 5, 202, 38, 147, 118, 126, 255, 82, 85, 212, 207, 206, 59, 227, 47, 16, 58, 17, 182, 189, + 28, 42, 223, 183, 170, 213, 119, 248, 152, 2, 44, 154, 163, 70, 221, 153, 101, 155, 167, 43, 172, 9, 129, + 22, 39, 253, 19, 98, 108, 110, 79, 113, 224, 232, 178, 185, 112, 104, 218, 246, 97, 228, 251, 34, 242, 193, + 238, 210, 144, 12, 191, 179, 162, 241, 81, 51, 145, 235, 249, 14, 239, 107, 49, 192, 214, 31, 181, 199, + 106, 157, 184, 84, 204, 176, 115, 121, 50, 45, 127, 4, 150, 254, 138, 236, 205, 93, 222, 114, 67, 29, 24, + 72, 243, 141, 128, 195, 78, 66, 215, 61, 156, 180 }; + static { + for (int i = 0; i < 256; i++) + p[256 + i] = p[i] = permutation[i]; + } +} diff --git a/src/ru/olamedia/olacraft/world/generator/Lerp.java b/src/ru/olamedia/olacraft/world/generator/Lerp.java new file mode 100644 index 0000000..cc009fe --- /dev/null +++ b/src/ru/olamedia/olacraft/world/generator/Lerp.java @@ -0,0 +1,27 @@ +package ru.olamedia.olacraft.world.generator; + +public class Lerp { + public static float lerp(float x, float x1, float x2, float q00, float q01) { + return ((x2 - x) / (x2 - x1)) * q00 + ((x - x1) / (x2 - x1)) * q01; + } + + public static float biLerp(float x, float y, float q11, float q12, float q21, float q22, float x1, float x2, + float y1, float y2) { + float r1 = lerp(x, x1, x2, q11, q21); + float r2 = lerp(x, x1, x2, q12, q22); + + return lerp(y, y1, y2, r1, r2); + } + + public static float triLerp(float x, float y, float z, float q000, float q001, float q010, float q011, float q100, + float q101, float q110, float q111, float x1, float x2, float y1, float y2, float z1, float z2) { + float x00 = lerp(x, x1, x2, q000, q100); + float x10 = lerp(x, x1, x2, q010, q110); + float x01 = lerp(x, x1, x2, q001, q101); + float x11 = lerp(x, x1, x2, q011, q111); + float r0 = lerp(y, y1, y2, x00, x01); + float r1 = lerp(y, y1, y2, x10, x11); + + return lerp(z, z1, z2, r0, r1); + } +} diff --git a/src/ru/olamedia/olacraft/world/generator/RegionGenerator.java b/src/ru/olamedia/olacraft/world/generator/RegionGenerator.java new file mode 100644 index 0000000..9657e32 --- /dev/null +++ b/src/ru/olamedia/olacraft/world/generator/RegionGenerator.java @@ -0,0 +1,71 @@ +package ru.olamedia.olacraft.world.generator; + +import ru.olamedia.olacraft.world.data.ChunkData; +import ru.olamedia.olacraft.world.data.HeightMap; +import ru.olamedia.olacraft.world.data.RegionData; +import ru.olamedia.olacraft.world.data.SectorData; +import ru.olamedia.olacraft.world.location.BlockLocation; +import ru.olamedia.olacraft.world.location.ChunkLocation; +import ru.olamedia.olacraft.world.location.SectorLocation; + +public class RegionGenerator { + private int[] seed; + + public void setSeed(int[] seed) { + this.seed = seed; + } + + public void debug(String s) { + System.out.println("[RegionGenerator] " + s); + } + + public void generate(RegionData data) { + HeightMapGenerator.minValue = -5; + HeightMapGenerator.maxValue = 100; + HeightMapGenerator.init(); + HeightMapGenerator.seed = seed[0]; + BlockLocation offset = data.location.getBlockLocation(); + // int[][] heightMap = + // HeightMapGenerator.getHeightMap(data.location.getBlockLocation().x, + // data.location.getBlockLocation().z, 256, 256); + debug(data.location.toString()); + data.heightMap = HeightMapGenerator.getHeightMap(data.location); + //debug(data.heightMap.toString()); + data.sectorData = new SectorData[16][16]; + for (int x = 0; x < 16; x++) { + for (int z = 0; z < 16; z++) { + // CREATE SECTOR + SectorData sector = new SectorData(); + sector.location = new SectorLocation(offset.x + x * 16, offset.z + z * 16); + sector.heightMap = new HeightMap(16, 16); + sector.chunkData = new ChunkData[16]; + for (int y = 0; y < 16; y++) { + // CREATE CHUNK + ChunkData chunk = new ChunkData(); + chunk.location = new ChunkLocation(sector.location.x, y, sector.location.z); + int chunkOffsetY = y * 16 - 128; + for (int inChunkX = 0; inChunkX < 16; inChunkX++) { + for (int inChunkZ = 0; inChunkZ < 16; inChunkZ++) { + int height = data.heightMap.getHeight(x * 16 + inChunkX, z * 16 + inChunkZ); + //System.out.println("height: " + height); + sector.heightMap.setHeight(inChunkX, inChunkZ, height); + for (int inChunkY = 0; inChunkY < 16; inChunkY++) { + //height = sector.heightMap.getHeight(inChunkX, inChunkZ); + int id = ChunkData.getId(inChunkX, inChunkY, inChunkZ); + if (chunkOffsetY + inChunkY > height) { + chunk.setEmpty(id, true); + } else { + //System.out.println("not empty, height: " + height); + chunk.setEmpty(id, false); + } + } + } + } + chunk.compact(); + sector.chunkData[y] = chunk; + } + data.sectorData[x][z] = sector; + } + } + } +} diff --git a/src/ru/olamedia/olacraft/world/generator/package-info.java b/src/ru/olamedia/olacraft/world/generator/package-info.java new file mode 100644 index 0000000..2f62117 --- /dev/null +++ b/src/ru/olamedia/olacraft/world/generator/package-info.java @@ -0,0 +1,8 @@ +/** + * + */ +/** + * @author olamedia + * + */ +package ru.olamedia.olacraft.world.generator;
\ No newline at end of file diff --git a/src/ru/olamedia/olacraft/world/location/BlockLocation.java b/src/ru/olamedia/olacraft/world/location/BlockLocation.java new file mode 100644 index 0000000..b104bad --- /dev/null +++ b/src/ru/olamedia/olacraft/world/location/BlockLocation.java @@ -0,0 +1,37 @@ +package ru.olamedia.olacraft.world.location; + +import java.io.Serializable; + +import ru.olamedia.olacraft.world.chunk.Chunk; + +public class BlockLocation implements Serializable { + private static final long serialVersionUID = -4987461467575474762L; + public int x; + public int y; + public int z; + + public BlockLocation() { + } + + public BlockLocation(int x, int y, int z) { + this.x = x; + this.y = y; + this.z = z; + } + + public ChunkLocation getChunkLocation() { + return new ChunkLocation(Chunk.v(x), Chunk.v(y + 128), Chunk.v(z)); + } + + public RegionLocation getRegionLocation() { + return new RegionLocation(Chunk.v(Chunk.v(x)), Chunk.v(Chunk.v(z))); + } + + public SectorLocation getSectorLocation() { + return new SectorLocation(Chunk.v(x), Chunk.v(z)); + } + + public String toString() { + return "blockLocation[" + x + "," + y + "," + z + "]"; + } +} diff --git a/src/ru/olamedia/olacraft/world/location/ChunkLocation.java b/src/ru/olamedia/olacraft/world/location/ChunkLocation.java new file mode 100644 index 0000000..57acc52 --- /dev/null +++ b/src/ru/olamedia/olacraft/world/location/ChunkLocation.java @@ -0,0 +1,40 @@ +package ru.olamedia.olacraft.world.location; + +import java.io.Serializable; + +import ru.olamedia.olacraft.world.chunk.Chunk; + +public class ChunkLocation implements Serializable { + private static final long serialVersionUID = -3620722885522274470L; + + public ChunkLocation() { + + } + + public ChunkLocation(int x, int y, int z) { + this.x = x; + this.y = y; + this.z = z; + } + + public int x; + public int y; + public int z; + + public SectorLocation getSectorLocation() { + return new SectorLocation(x, z); + } + + public RegionLocation getRegionLocation() { + return new RegionLocation(Chunk.v(x), Chunk.v(z)); + } + + public String toString() { + return "chunkLocation[" + x + "," + y + "," + z + "]"; + } + /* + * public BlockSlice getSlice(){ + * + * } + */ +} diff --git a/src/ru/olamedia/olacraft/world/location/RegionLocation.java b/src/ru/olamedia/olacraft/world/location/RegionLocation.java new file mode 100644 index 0000000..59a57ec --- /dev/null +++ b/src/ru/olamedia/olacraft/world/location/RegionLocation.java @@ -0,0 +1,29 @@ +package ru.olamedia.olacraft.world.location; + +import java.io.Serializable; + +public class RegionLocation implements Serializable { + private static final long serialVersionUID = -141619138379029773L; + public int x; + public int z; + + public RegionLocation() { + } + + public RegionLocation(int x, int z) { + this.x = x; + this.z = z; + } + + public String toString() { + return "regionLocation[" + x + "," + z + "]"; + } + + public String getFilename() { + return "" + x + "_" + z + ".region"; + } + + public BlockLocation getBlockLocation() { + return new BlockLocation(x * 256, 0, z * 256); + } +} diff --git a/src/ru/olamedia/olacraft/world/location/SectorLocation.java b/src/ru/olamedia/olacraft/world/location/SectorLocation.java new file mode 100644 index 0000000..59390b8 --- /dev/null +++ b/src/ru/olamedia/olacraft/world/location/SectorLocation.java @@ -0,0 +1,29 @@ +package ru.olamedia.olacraft.world.location; + +import java.io.Serializable; + +import ru.olamedia.olacraft.world.chunk.Chunk; + +public class SectorLocation implements Serializable { + private static final long serialVersionUID = 4500216114186249375L; + + public SectorLocation() { + + } + + public SectorLocation(int x, int z) { + this.x = x; + this.z = z; + } + + public int x; + public int z; + + public RegionLocation getRegionLocation() { + return new RegionLocation(Chunk.v(x), Chunk.v(z)); + } + + public String toString() { + return "sectorLocation[" + x + "," + z + "]"; + } +} diff --git a/src/ru/olamedia/olacraft/world/location/package-info.java b/src/ru/olamedia/olacraft/world/location/package-info.java new file mode 100644 index 0000000..37f205d --- /dev/null +++ b/src/ru/olamedia/olacraft/world/location/package-info.java @@ -0,0 +1,8 @@ +/** + * + */ +/** + * @author olamedia + * + */ +package ru.olamedia.olacraft.world.location;
\ No newline at end of file diff --git a/src/ru/olamedia/olacraft/world/package-info.java b/src/ru/olamedia/olacraft/world/package-info.java new file mode 100644 index 0000000..914d8d2 --- /dev/null +++ b/src/ru/olamedia/olacraft/world/package-info.java @@ -0,0 +1,8 @@ +/** + * + */ +/** + * @author olamedia + * + */ +package ru.olamedia.olacraft.world;
\ No newline at end of file diff --git a/src/ru/olamedia/olacraft/world/provider/IChunkProvider.java b/src/ru/olamedia/olacraft/world/provider/IChunkProvider.java new file mode 100644 index 0000000..5076c75 --- /dev/null +++ b/src/ru/olamedia/olacraft/world/provider/IChunkProvider.java @@ -0,0 +1,8 @@ +package ru.olamedia.olacraft.world.provider; + +import ru.olamedia.olacraft.world.block.Block; + +public interface IChunkProvider { + public boolean isEmptyBlock(int x, int y, int z); + public Block getBlock(int x, int y, int z); +} diff --git a/src/ru/olamedia/olacraft/world/provider/WorldProvider.java b/src/ru/olamedia/olacraft/world/provider/WorldProvider.java new file mode 100644 index 0000000..8dacce9 --- /dev/null +++ b/src/ru/olamedia/olacraft/world/provider/WorldProvider.java @@ -0,0 +1,130 @@ +package ru.olamedia.olacraft.world.provider; + +import ru.olamedia.olacraft.game.SpawnLocation; +import ru.olamedia.olacraft.world.WorldInfo; +import ru.olamedia.olacraft.world.block.Block; +import ru.olamedia.olacraft.world.chunk.Chunk; +import ru.olamedia.olacraft.world.data.ChunkData; +import ru.olamedia.olacraft.world.data.RegionData; +import ru.olamedia.olacraft.world.dataProvider.AbstractChunkDataProvider; +import ru.olamedia.olacraft.world.location.BlockLocation; +import ru.olamedia.olacraft.world.location.ChunkLocation; +import ru.olamedia.olacraft.world.location.RegionLocation; + +public class WorldProvider { + private WorldInfo info = new WorldInfo(); + private AbstractChunkDataProvider dataProvider; + + public WorldInfo getInfo() { + return info; + } + + public void setInfo(WorldInfo worldInfo) { + info = worldInfo; + } + + /* + * public AbstractChunkDataProvider getChunkDataProvider() { + * return dataProvider; + * } + */ + + public void setChunkDataProvider(AbstractChunkDataProvider provider) { + dataProvider = provider; + } + + public SpawnLocation getSpawnLocation(int connectionId) { + SpawnLocation l = new SpawnLocation(); + int maxShift = 10; + l.x = (int) (maxShift - Math.random() * 2 * maxShift); + l.z = (int) (maxShift - Math.random() * 2 * maxShift); + System.out.print("Searching spawn Y"); + BlockLocation spawnLocation = new BlockLocation(l.x, 0, l.z); + for (int y = info.maxHeight; y > info.minHeight; y--) { + // search for floor block + spawnLocation.y = y; + System.out.print(y + ". "); + ChunkData chunk = dataProvider.getChunk(spawnLocation.getChunkLocation()); + boolean notEmpty = !chunk.isEmpty(ChunkData.getId(Chunk.in(spawnLocation.x), Chunk.in(spawnLocation.y), + Chunk.in(spawnLocation.z))); + if (notEmpty) { + // found + l.y = y + 1; + System.out.println("found: " + y); + return l; + } + } + System.out.println("not found "); + // not found + l.y = info.maxHeight; + return l; + } + + public boolean renderBottom(int x, int y, int z) { + return (!isEmptyBlock(x, y, z)) && (isEmptyBlock(x, y - 1, z)); + } + + public boolean renderTop(int x, int y, int z) { + return (!isEmptyBlock(x, y, z)) && (isEmptyBlock(x, y + 1, z)); + } + + public boolean renderLeft(int x, int y, int z) { + return (!isEmptyBlock(x, y, z)) && (isEmptyBlock(x - 1, y, z)); + } + + public boolean renderRight(int x, int y, int z) { + return (!isEmptyBlock(x, y, z)) && (isEmptyBlock(x + 1, y, z)); + } + + public boolean renderBack(int x, int y, int z) { + return (!isEmptyBlock(x, y, z)) && (isEmptyBlock(x, y, z - 1)); + } + + public boolean renderFront(int x, int y, int z) { + return (!isEmptyBlock(x, y, z)) && (isEmptyBlock(x, y, z + 1)); + } + + public boolean isEmptyBlock(int x, int y, int z) { + BlockLocation blockLocation = new BlockLocation(x, y, z); + + if (isChunkAvailable(blockLocation.getChunkLocation())) { + ChunkData data = dataProvider.getChunk(blockLocation.getChunkLocation()); + if (null != data) { + return data.isEmpty(blockLocation); + } + } + return false; + } + + public void requestChunk(int chunkX, int chunkY, int chunkZ) { + ChunkLocation chunkLocation = new ChunkLocation(chunkX, chunkY, chunkZ); + // getChunkDataProvider().loadRegion(chunkLocation.getRegionLocation()); + loadChunk(chunkLocation); + } + + public boolean isChunkAvailable(ChunkLocation chunkLocation) { + return dataProvider.isChunkAvailable(chunkLocation); + } + + public boolean isAvailableBlock(int x, int y, int z) { + BlockLocation blockLocation = new BlockLocation(x, y, z); + return dataProvider.isChunkAvailable(blockLocation.getChunkLocation()); + } + + public void loadChunk(ChunkLocation chunkLocation) { + dataProvider.loadChunk(chunkLocation); + } + + public RegionData getRegion(RegionLocation regionLocation) { + return dataProvider.getRegion(regionLocation); + } + + public Block getBlock(int x, int y, int z) { + BlockLocation blockLocation = new BlockLocation(x, y, z); + return new Block(this, x, y, z); + } + + public ChunkData getChunk(ChunkLocation chunkLocation) { + return dataProvider.getChunk(chunkLocation); + } +} diff --git a/src/ru/olamedia/olacraft/world/provider/blockData/BlockData.java b/src/ru/olamedia/olacraft/world/provider/blockData/BlockData.java new file mode 100644 index 0000000..94be4d7 --- /dev/null +++ b/src/ru/olamedia/olacraft/world/provider/blockData/BlockData.java @@ -0,0 +1,5 @@ +package ru.olamedia.olacraft.world.provider.blockData; + +public class BlockData { + +} diff --git a/src/ru/olamedia/olacraft/world/provider/blockData/EmptyBlockData.java b/src/ru/olamedia/olacraft/world/provider/blockData/EmptyBlockData.java new file mode 100644 index 0000000..ab17107 --- /dev/null +++ b/src/ru/olamedia/olacraft/world/provider/blockData/EmptyBlockData.java @@ -0,0 +1,5 @@ +package ru.olamedia.olacraft.world.provider.blockData; + +public class EmptyBlockData implements IBlockData{ + public boolean notEmpty = false; +} diff --git a/src/ru/olamedia/olacraft/world/provider/blockData/IBlockData.java b/src/ru/olamedia/olacraft/world/provider/blockData/IBlockData.java new file mode 100644 index 0000000..95dfb35 --- /dev/null +++ b/src/ru/olamedia/olacraft/world/provider/blockData/IBlockData.java @@ -0,0 +1,5 @@ +package ru.olamedia.olacraft.world.provider.blockData; + +public interface IBlockData { + public boolean notEmpty = false; +} diff --git a/src/ru/olamedia/olacraft/world/provider/blockData/package-info.java b/src/ru/olamedia/olacraft/world/provider/blockData/package-info.java new file mode 100644 index 0000000..0fa952a --- /dev/null +++ b/src/ru/olamedia/olacraft/world/provider/blockData/package-info.java @@ -0,0 +1,8 @@ +/** + * + */ +/** + * @author olamedia + * + */ +package ru.olamedia.olacraft.world.provider.blockData;
\ No newline at end of file diff --git a/src/ru/olamedia/olacraft/world/provider/package-info.java b/src/ru/olamedia/olacraft/world/provider/package-info.java new file mode 100644 index 0000000..c43643a --- /dev/null +++ b/src/ru/olamedia/olacraft/world/provider/package-info.java @@ -0,0 +1,8 @@ +/** + * + */ +/** + * @author olamedia + * + */ +package ru.olamedia.olacraft.world.provider;
\ No newline at end of file diff --git a/src/ru/olamedia/player/Player.java b/src/ru/olamedia/player/Player.java new file mode 100644 index 0000000..08811b5 --- /dev/null +++ b/src/ru/olamedia/player/Player.java @@ -0,0 +1,31 @@ +package ru.olamedia.player; + +import ru.olamedia.liveEntity.LiveEntity; +import ru.olamedia.olacraft.game.Game; +import ru.olamedia.olacraft.network.packet.LiveEntityLocationUpdatePacket; +import ru.olamedia.olacraft.weapon.Bullet; + +public class Player extends LiveEntity { + + @Override + public void notifyLocationUpdate() { + LiveEntityLocationUpdatePacket p = new LiveEntityLocationUpdatePacket(); + p.x = getX(); + p.y = getY(); + p.z = getZ(); + Game.client.send(p); + } + + public Player() { + + } + + public void onMouseClick() { + Bullet b = new Bullet(); + b.velocity.set(Game.instance.camera.getLook()); + b.velocity.negate(); + b.velocity.scale(100); + b.location.set(getX(), getCameraY(), getZ()); + Game.client.getScene().addBullet(b); + } +} diff --git a/src/ru/olamedia/tasks/Task.java b/src/ru/olamedia/tasks/Task.java new file mode 100644 index 0000000..1886265 --- /dev/null +++ b/src/ru/olamedia/tasks/Task.java @@ -0,0 +1,24 @@ +package ru.olamedia.tasks; + +public abstract class Task implements Runnable { + + public Task(){ + TaskManager.add(this); + } + + protected volatile boolean stopped = false; + + public void setStopped(boolean s){ + this.stopped = s; + } + + public void stop() { + this.stopped = true; + } + + protected boolean shouldStop() { + return this.stopped; + } + + public abstract void run(); +} diff --git a/src/ru/olamedia/tasks/TaskManager.java b/src/ru/olamedia/tasks/TaskManager.java new file mode 100644 index 0000000..e1a637e --- /dev/null +++ b/src/ru/olamedia/tasks/TaskManager.java @@ -0,0 +1,18 @@ +package ru.olamedia.tasks; + +import java.util.ArrayList; +import java.util.List; + +public class TaskManager { + private static List<Task> tasks = new ArrayList<Task>(); + + public static void add(Task task) { + tasks.add(task); + } + + public static void stopAll() { + for (Task task : tasks) { + task.stop(); + } + } +} diff --git a/src/ru/olamedia/tasks/package-info.java b/src/ru/olamedia/tasks/package-info.java new file mode 100644 index 0000000..88dffa7 --- /dev/null +++ b/src/ru/olamedia/tasks/package-info.java @@ -0,0 +1,8 @@ +/** + * + */ +/** + * @author olamedia + * + */ +package ru.olamedia.tasks;
\ No newline at end of file diff --git a/src/ru/olamedia/texture/ResourceUtil.java b/src/ru/olamedia/texture/ResourceUtil.java new file mode 100644 index 0000000..656e3a8 --- /dev/null +++ b/src/ru/olamedia/texture/ResourceUtil.java @@ -0,0 +1,126 @@ +package ru.olamedia.texture; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.net.MalformedURLException; +import java.net.URISyntaxException; +import java.net.URL; + +public class ResourceUtil { + + private static URL baseURL; + + private static ResourceUtil instance; + + public static ResourceUtil getInstance() { + if (null == instance) { + instance = new ResourceUtil(); + } + return instance; + } + + public static URL getInternalBaseURL() { + if (null == baseURL) { + URL url = getInstance().getClass().getResource("ResourceUtil.class"); + // URL back = null; + // try { + // back = new URL(url, ".."); + // } catch (MalformedURLException e1) { + // e1.printStackTrace(); + // } + // System.out.println("Back:" + back); + // System.out.println("Class:" + url); + int p = url.toString().indexOf("jar!"); + if (p > 0) { + // in local jar: + // jar:file:/E:/com/mindprod/thepackage/thepackage.jar!/com/mindprod/thepackage/images/blueball.gif + // in remote jar: + // jar:http://mindprod.com/thepackage.jar!/com/mindprod/thepackage/images/blueball.gif + try { + baseURL = new URL(url.toString().substring(0, p + 4)); + } catch (MalformedURLException e) { + e.printStackTrace(); + } + } else { + // in local file: + // file:/E:/com/mindprod/thepackage/images/blueball.gif + // in remote file: + // http://mindprod.com/com/mindprod/the...s/blueball.gif + int l = url.toString().length() - (ResourceUtil.class.toString()).length(); + try { + baseURL = new URL(url.toString().substring(0, l)); + } catch (MalformedURLException e) { + e.printStackTrace(); + } + } + } + return baseURL; + } + + public static String getInternalFilename(String fn) { + return getInternalBaseURL() + fn; + } + + public static URL getInternalResource(String internalPath) throws MalformedURLException { + URL url = ResourceUtil.class.getClassLoader().getResource(internalPath); + if (url == null) { + System.out.println(internalPath + " not found"); + } else { + System.out.println(url.toString()); + } + return url; + // return new URL(getInternalBaseURL(), internalPath); + } + + public static URL getURL(String internalPath) { + try { + return new URL(getInternalBaseURL(), internalPath); + } catch (MalformedURLException e) { + e.printStackTrace(); + } + return null; + } + + public static String getFilename(String internalPath) { + try { + URL url = new URL(getInternalBaseURL(), internalPath); + return url.getFile(); + } catch (MalformedURLException e) { + System.err.println("Problems with " + internalPath); + e.printStackTrace(); + } + return null; + } + + public static InputStream getInternalInputStream(String internalPath) { + try { + return getInternalResource(internalPath).openStream(); + } catch (MalformedURLException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } + return null; + } + + public static File getFile(String fn) { + URL url = null; + try { + url = new URL(getInternalFilename(fn)); + } catch (MalformedURLException e1) { + e1.printStackTrace(); + } + System.out.println("Fn:" + fn); + System.out.println("Base:" + getInternalBaseURL()); + System.out.println("Internal:" + getInternalFilename(fn)); + System.out.println("Url:" + url); + File f; + try { + f = new File(url.toURI()); + } catch (URISyntaxException e) { + f = new File(url.getPath()); + } + return f; + } +} diff --git a/src/ru/olamedia/texture/TextureManager.java b/src/ru/olamedia/texture/TextureManager.java new file mode 100644 index 0000000..c790cee --- /dev/null +++ b/src/ru/olamedia/texture/TextureManager.java @@ -0,0 +1,42 @@ +package ru.olamedia.texture; + +import java.io.IOException; +import java.io.InputStream; +import java.util.HashMap; + +import ru.olamedia.asset.AssetManager; +import ru.olamedia.asset.AssetNotFoundException; + +import com.jogamp.opengl.util.texture.Texture; +import com.jogamp.opengl.util.texture.TextureIO; + +public class TextureManager { + private static HashMap<String, Texture> list = new HashMap<String, Texture>(); + + public static Texture get(String filename) { + if (!list.containsKey(filename)) { + try { + return get(filename, AssetManager.getAsset(filename).getInputStream()); + } catch (IOException e) { + e.printStackTrace(); + return null; + } catch (AssetNotFoundException e) { + e.printStackTrace(); + return null; + } + } + return list.get(filename); + } + + public static Texture get(String key, InputStream stream) { + if (!list.containsKey(key)) { + try { + list.put(key, TextureIO.newTexture(stream, true, "PNG")); + } catch (IOException e) { + list.put(key, null); + e.printStackTrace(); + } + } + return list.get(key); + } +} diff --git a/src/ru/olamedia/texture/package-info.java b/src/ru/olamedia/texture/package-info.java new file mode 100644 index 0000000..fb1a5d4 --- /dev/null +++ b/src/ru/olamedia/texture/package-info.java @@ -0,0 +1,8 @@ +/** + * + */ +/** + * @author olamedia + * + */ +package ru.olamedia.texture;
\ No newline at end of file diff --git a/src/ru/olamedia/util/BufferUtils.java b/src/ru/olamedia/util/BufferUtils.java new file mode 100644 index 0000000..10d9f36 --- /dev/null +++ b/src/ru/olamedia/util/BufferUtils.java @@ -0,0 +1,16 @@ +package ru.olamedia.util; + +import java.nio.FloatBuffer; +import java.nio.ShortBuffer; + +public class BufferUtils { + + public static ShortBuffer createShortBuffer(int capacity) { + return ShortBuffer.allocate(capacity); + } + + public static FloatBuffer createFloatBuffer(int capacity) { + return FloatBuffer.allocate(capacity); + } + +} diff --git a/src/ru/olamedia/vbo/VBO.java b/src/ru/olamedia/vbo/VBO.java new file mode 100644 index 0000000..6f6c508 --- /dev/null +++ b/src/ru/olamedia/vbo/VBO.java @@ -0,0 +1,29 @@ +package ru.olamedia.vbo; + +import javax.media.opengl.GL2ES2; +import javax.media.opengl.GLAutoDrawable; +import javax.media.opengl.GLUniformData; + +import com.jogamp.opengl.util.PMVMatrix; + +public class VBO { + private GLAutoDrawable drawable; + private PMVMatrix pmvMatrix; + private GLUniformData pmvMatrixUniform; + private GLUniformData colorUniform; + private int[] vboIda = new int[10]; + + public VBO(GLAutoDrawable drawable) { + this.drawable = drawable; + GL2ES2 gl = drawable.getGL().getGL2ES2(); + // gl.glGenBuffersARB(1, vboIda, 0); + } + + public void setDrawable(GLAutoDrawable drawable) { + this.drawable = drawable; + } + + public void render() { + + } +} diff --git a/src/ru/olamedia/vbo/package-info.java b/src/ru/olamedia/vbo/package-info.java new file mode 100644 index 0000000..325d96f --- /dev/null +++ b/src/ru/olamedia/vbo/package-info.java @@ -0,0 +1,8 @@ +/** + * + */ +/** + * @author olamedia + * + */ +package ru.olamedia.vbo;
\ No newline at end of file |