blob: f510f9079e7bcf61cbf87ee0d19908b5bf130ac7 [file] [log] [blame]
/**
* Copyright (c) 2011, Novyon Events
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* - 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER 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.
*
* @author Anthyon
*/
package com.jme3.terrain.noise.filter;
import java.nio.FloatBuffer;
import java.util.logging.Logger;
import com.jme3.terrain.noise.ShaderUtils;
import com.jme3.terrain.noise.fractal.FractalSum;
public class PerturbFilter extends AbstractFilter {
private float magnitude;
@Override
public int getMargin(int size, int margin) {
margin = super.getMargin(size, margin);
return (int) Math.floor(this.magnitude * (margin + size) + margin);
}
public void setMagnitude(float magnitude) {
this.magnitude = magnitude;
}
public float getMagnitude() {
return this.magnitude;
}
@Override
public FloatBuffer filter(float sx, float sy, float base, FloatBuffer data, int workSize) {
float[] arr = data.array();
int origSize = (int) Math.ceil(workSize / (2 * this.magnitude + 1));
int offset = (workSize - origSize) / 2;
Logger.getLogger(PerturbFilter.class.getCanonicalName()).info(
"Found origSize : " + origSize + " and offset: " + offset + " for workSize : " + workSize + " and magnitude : "
+ this.magnitude);
float[] retval = new float[workSize * workSize];
float[] perturbx = new FractalSum().setOctaves(8).setScale(5f).getBuffer(sx, sy, base, workSize).array();
float[] perturby = new FractalSum().setOctaves(8).setScale(5f).getBuffer(sx, sy, base + 1, workSize).array();
for (int y = 0; y < workSize; y++) {
for (int x = 0; x < workSize; x++) {
// Perturb our coordinates
float noisex = perturbx[y * workSize + x];
float noisey = perturby[y * workSize + x];
int px = (int) (origSize * noisex * this.magnitude);
int py = (int) (origSize * noisey * this.magnitude);
float c00 = arr[this.wrap(y - py, workSize) * workSize + this.wrap(x - px, workSize)];
float c01 = arr[this.wrap(y - py, workSize) * workSize + this.wrap(x + px, workSize)];
float c10 = arr[this.wrap(y + py, workSize) * workSize + this.wrap(x - px, workSize)];
float c11 = arr[this.wrap(y + py, workSize) * workSize + this.wrap(x + px, workSize)];
float c0 = ShaderUtils.mix(c00, c01, noisex);
float c1 = ShaderUtils.mix(c10, c11, noisex);
retval[y * workSize + x] = ShaderUtils.mix(c0, c1, noisey);
}
}
return FloatBuffer.wrap(retval);
}
private int wrap(int v, int size) {
if (v < 0) {
return v + size - 1;
} else if (v >= size) {
return v - size;
} else {
return v;
}
}
}