Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- public class OlsenNoise2DColors {
- public static final int SCALE_FACTOR = 2;
- //The scale factor is kind of arbitrary, but the code is only consistent for 2 currently. Gives noise for other scale but not location proper.
- private static final int blurEdge = 2; //extra pixels are needed for the blur (3 - 1).
- /**
- * Function adds all the required ints into the ints array.
- * Note that the scanline should not actually equal the width.
- * It should be larger as per the getRequiredDim function.
- *
- * @param iterations Number of iterations to perform.
- * @param ints pixel array to be used to insert values. (Pass by reference)
- * @param stride distance in the array to the next requestedY value.
- * @param x requested X location.
- * @param y requested Y location.
- * @param width width of the image.
- * @param height height of the image.
- */
- public static void olsennoise(int iterations, int[] ints, int stride, int x, int y, int width, int height) {
- olsennoise(ints, stride, x, y, width, height, iterations); //Calls the main routine.
- applyMask(ints, stride, width, height, 0xFF000000);
- }
- private static void applyMask(int[] pixels, int stride, int width, int height, int mask) {
- int index;
- index = 0;
- for (int k = 0, n = height - 1; k <= n; k++, index += stride) {
- for (int j = 0, m = width - 1; j <= m; j++) {
- pixels[index + j] |= mask;
- }
- }
- }
- /**
- * Converts a dimension into the dimension required by the algorithm.
- * Due to the blurring, to get valid data the array must be slightly larger.
- * Due to the interpixel location at lowest levels it needs to be bigger by
- * the max value that can be. (SCALE_FACTOR)
- *
- * @param dim
- * @return
- */
- public static int getRequiredDim(int dim) {
- return dim + blurEdge + SCALE_FACTOR;
- }
- //Function inserts the values into the given ints array (pass by reference)
- //The results will be within 0-255 assuming the requested iterations are 7.
- private static void olsennoise(int[] ints, int stride, int x_within_field, int y_within_field, int width, int height, int iteration) {
- if (iteration == 0) {
- //Base case. If we are at the bottom. Do not run the rest of the function. Return random values.
- clearValues(ints, stride, width, height); //base case needs zero, apply Noise will not eat garbage.
- applyNoise(ints, stride, x_within_field, y_within_field, width, height, iteration);
- return;
- }
- int x_remainder = x_within_field & 1; //Adjust the x_remainder so we know how much more into the pixel are.
- int y_remainder = y_within_field & 1; //Math.abs(y_within_field % SCALE_FACTOR) - Would be assumed for larger scalefactors.
- /*
- Pass the ints, and the stride for that set of ints.
- Recurse the call to the function moving the x_within_field forward if we actaully want half a pixel at the start.
- Same for the requestedY.
- The width should expanded by the x_remainder, and then half the size, with enough extra to store the extra ints from the blur.
- If the width is too long, it'll just run more stuff than it needs to.
- */
- olsennoise(ints, stride,
- ((x_within_field + x_remainder) / SCALE_FACTOR) - x_remainder,
- ((y_within_field + y_remainder) / SCALE_FACTOR) - y_remainder,
- ((width + x_remainder) / SCALE_FACTOR) + blurEdge,
- ((height + y_remainder) / SCALE_FACTOR) + blurEdge, iteration - 1);
- //This will scale the image from half the width and half the height. bounds.
- //The scale function assumes you have at least width/2 and height/2 good ints.
- //We requested those from olsennoise above, so we should have that.
- applyScaleShift(ints, stride, width + blurEdge, height + blurEdge, SCALE_FACTOR, x_remainder, y_remainder);
- //This applies the blur and uses the given bounds.
- //Since the blur loses two at the edge, this will result
- //in us having width requestedX height of good ints and required
- // width + blurEdge of good ints. height + blurEdge of good ints.
- applyBlur(ints, stride, width + blurEdge, height + blurEdge);
- //Applies noise to all the given ints. Does not require more or less than ints. Just offsets them all randomly.
- applyNoise(ints, stride, x_within_field, y_within_field, width, height, iteration);
- }
- private static void applyNoise(int[] pixels, int stride, int x_within_field, int y_within_field, int width, int height, int iteration) {
- long bitmask = 0b00000001000000010000000100000001 << (7-iteration);
- int index = 0;
- for (int k = 0, n = height - 1; k <= n; k++, index += stride) { //iterate the requestedY positions. Offsetting the index by stride each time.
- for (int j = 0, m = width - 1; j <= m; j++) { //iterate the requestedX positions through width.
- int current = index + j; // The current position of the pixel is the index which will have added stride each, requestedY iteration
- pixels[current] += hashrandom(j + x_within_field, k + y_within_field, iteration) & bitmask;
- //add on to this pixel the hash function with the set reduction.
- //It simply must scale down with the larger number of iterations.
- }
- }
- }
- private static void applyScaleShift(int[] pixels, int stride, int width, int height, int factor, int shiftX, int shiftY) {
- int index = (height - 1) * stride; //We must iteration backwards to scale so index starts at last Y position.
- for (int k = 0, n = height - 1; k <= n; n--, index -= stride) { // we iterate the requestedY, removing stride from index.
- for (int j = 0, m = width - 1; j <= m; m--) { // iterate the requestedX positions from width to 0.
- int pos = index + m; //current position is the index (position of that scanline of Y) plus our current iteration in scale.
- int lower = (((n+shiftY) / factor) * stride) + ((m+shiftX) / factor); //We find the position that is half that size. From where we scale them out.
- pixels[pos] = pixels[lower]; // Set the outer position to the inner position. Applying the scale.
- }
- }
- }
- private static void clearValues(int[] pixels, int stride, int width, int height) {
- int index;
- index = 0;
- for (int k = 0, n = height - 1; k <= n; k++, index += stride) { //iterate the requestedY values.
- for (int j = 0, m = width - 1; j <= m; j++) { //iterate the requestedX values.
- pixels[index + j] = 0; //clears those values.
- }
- }
- }
- //Applies the blur.
- //box blur 3x3 in each color. Really boxblur 1x3 and 3x1.
- private static void applyBlur(int[] pixels, int stride, int width, int height) {
- int index = 0;
- int v0;
- int v1;
- int v2;
- int r;
- int g;
- int b;
- for (int j = 0; j < height; j++, index += stride) {
- for (int k = 0; k < width; k++) {
- int pos = index + k;
- v0 = pixels[pos];
- v1 = pixels[pos+1];
- v2 = pixels[pos+2];
- r = ((v0 >> 16) & 0xFF) + ((v1 >> 16) & 0xFF) + ((v2 >> 16) & 0xFF);
- g = ((v0 >> 8 ) & 0xFF) + ((v1 >> 8) & 0xFF) + ((v2 >> 8) & 0xFF);
- b = ((v0 ) & 0xFF) + ((v1 ) & 0xFF) + ((v2 ) & 0xFF);
- r/=3;
- g/=3;
- b/=3;
- pixels[pos] = r << 16 | g << 8 | b;
- }
- }
- index = 0;
- for (int j = 0; j < height; j++, index += stride) {
- for (int k = 0; k < width; k++) {
- int pos = index + k;
- v0 = pixels[pos];
- v1 = pixels[pos+stride];
- v2 = pixels[pos+(stride<<1)];
- r = ((v0 >> 16) & 0xFF) + ((v1 >> 16) & 0xFF) + ((v2 >> 16) & 0xFF);
- g = ((v0 >> 8 ) & 0xFF) + ((v1 >> 8) & 0xFF) + ((v2 >> 8) & 0xFF);
- b = ((v0 ) & 0xFF) + ((v1 ) & 0xFF) + ((v2 ) & 0xFF);
- r/=3;
- g/=3;
- b/=3;
- pixels[pos] = r << 16 | g << 8 | b;
- }
- }
- }
- public static long hashrandom(int v0, int v1, int v2) {
- long hash = 0;
- hash ^= v0;
- hash = hash(hash);
- hash ^= v1;
- hash = hash(hash);
- hash ^= v2;
- hash = hash(hash);
- return hash;
- }
- private static long hash(long v) {
- long hash = v;
- long h = hash;
- switch ((int) hash & 3) {
- case 3:
- hash += h;
- hash ^= hash << 32;
- hash ^= h << 36;
- hash += hash >> 22;
- break;
- case 2:
- hash += h;
- hash ^= hash << 22;
- hash += hash >> 34;
- break;
- case 1:
- hash += h;
- hash ^= hash << 20;
- hash += hash >> 2;
- }
- hash ^= hash << 6;
- hash += hash >> 10;
- hash ^= hash << 8;
- hash += hash >> 34;
- hash ^= hash << 50;
- hash += hash >> 12;
- return hash;
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement